bitkeeper revision 1.1236.54.1 (424f001fylJD_smguTvRssBAMspunA)

First code drop for x86-64 support; further clenaups still required.

Signed-Off-By: Asit Mallick <asit.k.mallick@intel.com>
Signed-Off-By: Arun Sharma <arun.sharma@intel.com>
Signed-Off-By: Benjamin Liu <Benjamin.liu@intel.com>
Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
cl349@firebug.cl.cam.ac.uk[cl349] committed 2005-04-02 20:27:11 +00:00
1 parent 2244934123
commit 72b1fd4c80
71 files changed
+21128

No files matched your search

+70
View File
@@ -210,7 +210,9 @@
40f56237penAAlWVBVDpeQZNFIg8CA linux-2.6.11-xen-sparse/arch/xen/Makefile
40f56237JTc60m1FRlUxkUaGSQKrNw linux-2.6.11-xen-sparse/arch/xen/boot/Makefile
40f56237hRxbacU_3PdoAl6DjZ3Jnw linux-2.6.11-xen-sparse/arch/xen/configs/xen0_defconfig_x86_32
424f001dsaMEQ1wWQnPmu0ejo6pgPA linux-2.6.11-xen-sparse/arch/xen/configs/xen0_defconfig_x86_64
40f56237wubfjJKlfIzZlI3ZM2VgGA linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32
424f001dsBzCezYZD8vAn-h5D9ZRtQ linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64
40f56237Mta0yHNaMS_qtM2rge0qYA linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig
40f56238u2CJdXNpjsZgHBxeVyY-2g linux-2.6.11-xen-sparse/arch/xen/i386/Makefile
40f56238eczveJ86k_4hNxCLRQIF-g linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile
@@ -257,6 +259,40 @@
414c113396tK1HTVeUalm3u-1DF16g linux-2.6.11-xen-sparse/arch/xen/kernel/skbuff.c
418f90e4lGdeJK9rmbOB1kN-IKSjsQ linux-2.6.11-xen-sparse/arch/xen/kernel/smp.c
3f68905c5eiA-lBMQSvXLMWS1ikDEA linux-2.6.11-xen-sparse/arch/xen/kernel/xen_proc.c
424efaa6xahU2q85_dT-SjUJEaivfg linux-2.6.11-xen-sparse/arch/xen/x86_64/Kconfig
424efaa6kKleWe45IrqsG8gkejgEQA linux-2.6.11-xen-sparse/arch/xen/x86_64/Makefile
424efaa7hjpGexXRf5TYBwgP7uT5Wg linux-2.6.11-xen-sparse/arch/xen/x86_64/defconfig
424efaa6HSyuVodl6SxFGj39vlp6MA linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/Makefile
424efaa7bVAw3Z_q0SdFivfNVavyIg linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/asm-offsets.c
424efaa7ddTVabh547Opf0u9vKmUXw linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/e820.c
424efaa72fQEHYQ-Sp2IW9X2xTA5zQ linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/early_printk.c
424efaa7B_BWrAkLPJNoKk4EQY2a7w linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S
424efaa7vhgi7th5QVICjfuHmEWOkw linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/head.S
424efaa7tiMEZSAYepwyjaNWxyXF7Q linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/head64.c
424efaa6M6AGf53TJa2y9cl6coos0g linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/init_task.c
424efaa6wHXXaloZygAv6ywDb7u7nQ linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/ioport.c
424efaa6gOkc9_uHCLgvY_DXPqh_sg linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/irq.c
424efaa6ibN3xXEeXoxURmKfJF_CUA linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/ldt.c
424efaa6aX4JkXAzBf4nqxRmLUfhqQ linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/pci-dma.c
424efaa7e8nVw04q-pK8XRFaHPVx_A linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/pci-nommu.c
424efaa7CxY9cbhqapUfqVYnD7T9LQ linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/process.c
424efaa7I-DPzj1fkZeYPJS7rA4FAw linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c
424efaa7DIVTR1U4waPGHucha9Xilg linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup64.c
424efaa6L1lrzwCIadTNxogSvljFwg linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/signal.c
424efaa61XzweJyW3v5Lb9egpe3rtw linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/smp.c
424efaa778MkpdkAIq0An1FjQENN_Q linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/smpboot.c
424efaa7vzbNdhwhkQPhs1V7LrAH4Q linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/time.c
424efaa7szEu90xkjpXk5TufZxxa4g linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/traps.c
424efaa6sJsuHdGIGxm0r-ugsss3OQ linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/vsyscall.c
424efaa6xbX9LkKyaXvgbL9s_39Trw linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/x8664_ksyms.c
424efaa670zlQTtnOYK_aNgqhmSx-Q linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/Makefile
424efaa6HUC68-hBHgiWOMDfKZogIA linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/fault.c
424f001d6S-OiHsk1n9gv1jGwws-9w linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/hypervisor.c
424efaa65ELRJ3JfgQQKLzW6y0ECYQ linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/init.c
424efaa60dTbHfv65JBLVhNLcNPcRA linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/ioremap.c
424efaa6uMX8YJASAVJT8ral74dz9Q linux-2.6.11-xen-sparse/arch/xen/x86_64/mm/pageattr.c
424efaa629XgfZi3vvTAuQmhCqmvIA linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile
424efaa64SRL9FZhtQovFJAVh9sZlQ linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile-BUS
41261688yS8eAyy-7kzG4KBs0xbYCA linux-2.6.11-xen-sparse/drivers/Makefile
4108f5c1WfTIrs0HZFeV39sttekCTw linux-2.6.11-xen-sparse/drivers/char/mem.c
4111308bZAIzwf_Kzu6x1TZYZ3E0_Q linux-2.6.11-xen-sparse/drivers/char/tty_io.c
@@ -329,6 +365,39 @@
40f5623bVdKP7Dt7qm8twu3NcnGNbA linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h
40f5623bc8LKPRO09wY5dGDnY_YCpw linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/tlbflush.h
41062ab7uFxnCq-KtPeAm-aV8CicgA linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/vga.h
424f001delsctIT-_5gdbHsN9VfaQA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/arch_hooks.h
424efa21QfpO4QqQf9ADB4U_2zo8dQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/bootsetup.h
424efa21riixePBPesLRsVnhFxfEfQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/desc.h
424efa21iAXuoKIT3-zDni6aryFlPQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/dma-mapping.h
424efa21QCdU7W3An0BM0bboJZ6f4Q linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/fixmap.h
424efa21S7Ruo0JzTFH1qwezpdtCbw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/floppy.h
424f001ds3cL9WAgSH5Nja1BAkZfDg linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h
424efa20tMbuEQuxvPjow-wkBx83rA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/io.h
424efa20meDrUt6I2XWbpuf72e4gEw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/irq.h
424f001d3cpZoX9SZD_zjTapOs-ZIQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/io_ports.h
424f001eirTAXdX_1gCugGtzSGJUXw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h
424f001eTD7ATy8MC71Lm2rOHHyUCA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/mach_time.h
424f001ew4jIwfKeZUNa_U54UAaJcw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/mach_timer.h
424f001ePIPWhBJGeTgj-KmiHOYvqw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h
424f001e0S9hTGOoEN8pgheQJ76yqQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_pre.h
424f001eQPBrY1621DbCPKn9wK36ZQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h
424efa21FvJNdHFfm2w2TOWohNsqDQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mmu_context.h
424efa214neirHds4zbtwaefvG5PYA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/page.h
424efa21-7jaHj-W-T4E9oM3kqFA7Q linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/param.h
424efa20I76WtOlPh71MaXtai3-qZA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/pci.h
424efa20Fs7EHhAV6Hz_UtifwEfczg linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/pda.h
424efa20CGx-5HD8ahpdHxPW2KlrtA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/pgalloc.h
424efa21YaMjX7hz7eCkVNcNWRK42A linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/pgtable.h
424efa21wPKwwFR1fcqrPD0_o3GKWA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/processor.h
424efa20fTFqmaE0stH6lfB_4yN_lA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/ptrace.h
424efa21fY4IvK0luYgDJHKV-MD3eQ linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/segment.h
424efa21KcupuJlHgmPiTk_T214FrA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/smp.h
424f001eT-7wjT_7K5AMlNVigIcuHA linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/synch_bitops.h
424efa210ZRt2U_8WmtyI7g74Nz-4Q linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/system.h
424f001eBp9fMbZ0Mo2kRJQ84gMgRw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/timer.h
424efa21Xk2acvaHYnpyTCLE6nU6hw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/tlbflush.h
424efa21Ey6Q4L4AsXxcEwH3vMDeiw linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/vga.h
424efa214gNhOfFimFJHq4in24Yp1g linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/xor.h
41af4017PDMuSmMWtSRU5UC9Vylw5g linux-2.6.11-xen-sparse/include/asm-xen/balloon.h
40f5623bYNP7tHE2zX6YQxp9Zq2utQ linux-2.6.11-xen-sparse/include/asm-xen/ctrl_if.h
40f5623b3Eqs8pAc5WpPX8_jTzV2qw linux-2.6.11-xen-sparse/include/asm-xen/evtchn.h
@@ -387,6 +456,7 @@
413cb3b53nyOv1OIeDSsCXhBFDXvJA netbsd-2.0-xen-sparse/sys/nfs/files.nfs
413aa1d0oNP8HXLvfPuMe6cSroUfSA patches/linux-2.6.11/agpgart.patch
42372652KCUP-IOH9RN19YQmGhs4aA patches/linux-2.6.11/iomap.patch
424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Rules.mk
4209033eUwhDBJ_bxejiv5c6gjXS4A tools/blktap/Makefile
@@ -0,0 +1,703 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.10-xen0
# Tue Mar 15 10:39:50 2005
#
CONFIG_XEN=y
CONFIG_ARCH_XEN=y
CONFIG_NO_IDLE_HZ=y
#
# XEN
#
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_PHYSDEV_ACCESS=y
CONFIG_XEN_BLKDEV_BACKEND=y
# CONFIG_XEN_BLKDEV_TAP_BE is not set
CONFIG_XEN_NETDEV_BACKEND=y
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
# CONFIG_XEN_BLKDEV_TAP is not set
# CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
# CONFIG_XEN_X86 is not set
CONFIG_XEN_X86_64=y
CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
#
# Code maturity level options
#
# CONFIG_EXPERIMENTAL is not set
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_LOCALVERSION=""
# CONFIG_SWAP is not set
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_XENARCH="x86_64"
CONFIG_MMU=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
# CONFIG_MK8 is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_L1_CACHE_SHIFT=7
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_X86_GOOD_APIC=y
# CONFIG_HPET_TIMER is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
# CONFIG_MICROCODE is not set
# CONFIG_X86_CPUID is not set
# CONFIG_NUMA is not set
# CONFIG_MTRR is not set
CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
#
# X86_64 processor configuration
#
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_64BIT=y
#
# Processor type and features
#
# CONFIG_MPSC is not set
CONFIG_GENERIC_CPU=y
CONFIG_X86_L1_CACHE_BYTES=128
# CONFIG_X86_TSC is not set
# CONFIG_X86_MSR is not set
# CONFIG_GART_IOMMU is not set
CONFIG_DUMMY_IOMMU=y
# CONFIG_X86_MCE is not set
#
# Power management options
#
# CONFIG_PM is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
#
# CONFIG_ACPI is not set
# CONFIG_ACPI_BLACKLIST_YEAR=0
#
# CPU Frequency scaling
#
# CONFIG_CPU_FREQ is not set
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_LEGACY_PROC=y
# CONFIG_PCI_NAMES is not set
# CONFIG_PCI_MMCONFIG is not set
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
#
# Executable file formats / Emulations
#
# CONFIG_IA32_EMULATION is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER 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=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
#
# SCSI device support
#
CONFIG_SCSI=y
CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_CHR_DEV_OSST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
#
# SCSI Transport Attributes
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
#
# SCSI low-level drivers
#
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
CONFIG_SCSI_SATA=y
# CONFIG_SCSI_SATA_AHCI is not set
# CONFIG_SCSI_SATA_SVW is not set
CONFIG_SCSI_ATA_PIIX=y
# CONFIG_SCSI_SATA_NV is not set
CONFIG_SCSI_SATA_PROMISE=y
# CONFIG_SCSI_SATA_QSTOR is not set
CONFIG_SCSI_SATA_SX4=y
CONFIG_SCSI_SATA_SIL=y
# CONFIG_SCSI_SATA_SIS is not set
# CONFIG_SCSI_SATA_ULI is not set
# CONFIG_SCSI_SATA_VIA is not set
# CONFIG_SCSI_SATA_VITESSE is not set
CONFIG_SCSI_BUSLOGIC=y
# CONFIG_SCSI_OMIT_FLASHPOINT is not set
# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
CONFIG_SCSI_QLA2XXX=y
# CONFIG_SCSI_QLA21XX is not set
# CONFIG_SCSI_QLA22XX is not set
# CONFIG_SCSI_QLA2300 is not set
# CONFIG_SCSI_QLA2322 is not set
# CONFIG_SCSI_QLA6312 is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_NSP32 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
#
# CONFIG_IEEE1394 is not set
#
# I2O device support
#
# CONFIG_I2O is not set
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
# CONFIG_PACKET is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_UNIX 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_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE 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_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
# CONFIG_NETFILTER 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
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_NETDEVICES 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=y
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 I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PCIPS2 is not set
# CONFIG_SERIO_RAW is not set
#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
# 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=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set
#
# 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 is not set
# 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
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HANGCHECK_TIMER is not set
#
# I2C support
#
# CONFIG_I2C is not set
#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
#
# Misc devices
#
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
#
# Graphics support
#
# CONFIG_FB is not set
# CONFIG_VIDEO_SELECT is not set
#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
#
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY 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 is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_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=y
CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
CONFIG_DEVPTS_FS_XATTR=y
CONFIG_DEVPTS_FS_SECURITY=y
CONFIG_TMPFS=y
CONFIG_TMPFS_XATTR=y
CONFIG_TMPFS_SECURITY=y
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_HFSPLUS_FS is not set
# CONFIG_CRAMFS is not set
# 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 is not set
# CONFIG_NFSD is not set
# CONFIG_EXPORTFS 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
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_BSD_DISKLABEL=y
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
CONFIG_EFI_PARTITION=y
#
# Native Language Support
#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
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 is not set
# 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
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
CONFIG_CRC_CCITT=y
CONFIG_CRC32=y
CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
#
# Firmware Drivers
#
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
@@ -0,0 +1,513 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.10-xenU
# Mon Dec 27 10:15:03 2004
#
CONFIG_XEN=y
CONFIG_ARCH_XEN=y
CONFIG_NO_IDLE_HZ=y
#
# XEN
#
# CONFIG_XEN_PRIVILEGED_GUEST is not set
# CONFIG_XEN_PHYSDEV_ACCESS is not set
# CONFIG_XEN_BLKDEV_BACKEND is not set
# CONFIG_XEN_NETDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
# CONFIG_XEN_BLKDEV_TAP is not set
CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
CONFIG_X86=y
# CONFIG_X86_64 is not set
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
#
# General setup
#
CONFIG_LOCALVERSION=""
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
# X86 Processor Configuration
#
CONFIG_XENARCH="x86_64"
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
# 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 is not set
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
CONFIG_MPENTIUM4=y
# 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_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=7
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
# CONFIG_HPET_TIMER is not set
# CONFIG_HPET_EMULATE_RTC is not set
# CONFIG_SMP is not set
CONFIG_PREEMPT=y
CONFIG_X86_CPUID=y
#
# Firmware Drivers
#
# CONFIG_EDD is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
CONFIG_HAVE_DEC_LOCK=y
# CONFIG_REGPARM is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
CONFIG_EARLY_PRINTK=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_FRAME_POINTER is not set
# CONFIG_4KSTACKS is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_X86_BIOS_REBOOT=y
CONFIG_PC=y
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC 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
#
# Block devices
#
# CONFIG_BLK_DEV_FD 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_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
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
#
# 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
#
# SCSI low-level drivers
#
# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_DEBUG is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
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_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP 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_NET_DIVERT 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
# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
#
# 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_UNIX98_PTYS=y
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR 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_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
#
# 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_DEVFS_FS is not set
CONFIG_DEVPTS_FS_XATTR=y
# CONFIG_DEVPTS_FS_SECURITY is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# 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 is not set
# 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_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_EXPORTFS is not set
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
#
# 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
#
# 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_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_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
#
# Library routines
#
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
@@ -0,0 +1,463 @@
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
# Note: ISA is disabled and will hopefully never be enabled.
# If you managed to buy an ISA x86-64 box you'll have to fix all the
# ISA drivers you need yourself.
#
menu "X86_64 processor configuration"
depends XEN_X86_64
config XENARCH
string
default x86_64
config X86_64
bool
default y
help
Port to the x86-64 architecture. x86-64 is a 64-bit extension to the
classical 32-bit x86 architecture. For details see
<http://www.x86-64.org/>.
config X86
bool
default y
config 64BIT
def_bool y
#config X86
# bool
# default y
config MMU
bool
default y
config ISA
bool
config SBUS
bool
config RWSEM_GENERIC_SPINLOCK
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
config GENERIC_CALIBRATE_DELAY
bool
default y
config X86_CMPXCHG
bool
default y
config EARLY_PRINTK
bool "Early Printk"
default n
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 HPET_TIMER
bool
default n
help
Use the IA-PC HPET (High Precision Event Timer) to manage
time in preference to the PIT and RTC, if a HPET is
present. The HPET provides a stable time base on SMP
systems, unlike the RTC, but it is more expensive to access,
as it is off-chip. You can find the HPET spec at
<http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
If unsure, say Y.
config HPET_EMULATE_RTC
bool "Provide RTC interrupt"
depends on HPET_TIMER && RTC=y
config GENERIC_ISA_DMA
bool
default y
config GENERIC_IOMAP
bool
default y
#source "init/Kconfig"
menu "Processor type and features"
choice
prompt "Processor family"
default MK8
config MK8
bool "AMD-Opteron/Athlon64"
help
Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs.
config MPSC
bool "Intel x86-64"
help
Optimize for Intel IA32 with 64bit extension CPUs
(Prescott/Nocona/Potomac)
config GENERIC_CPU
bool "Generic-x86-64"
help
Generic x86-64 CPU.
endchoice
#
# Define implied options from the CPU selection here
#
config X86_L1_CACHE_BYTES
int
default "128" if GENERIC_CPU || MPSC
default "64" if MK8
config X86_L1_CACHE_SHIFT
int
default "7" if GENERIC_CPU || MPSC
default "6" if MK8
config X86_TSC
bool
default n
config X86_GOOD_APIC
bool
default y
config MICROCODE
tristate "/dev/cpu/microcode - Intel CPU microcode support"
---help---
If you say Y here the 'File systems' section, you will be
able to update the microcode on Intel processors. You will
obviously need the actual microcode binary data itself which is
not shipped with the Linux kernel.
For latest news and information on obtaining all the required
ingredients for this driver, check:
<http://www.urbanmyth.org/microcode/>.
To compile this driver as a module, choose M here: the
module will be called microcode.
If you use modprobe or kmod you may also want to add the line
'alias char-major-10-184 microcode' to your /etc/modules.conf file.
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
help
This device gives privileged processes access to the x86
Model-Specific Registers (MSRs). It is a character device with
major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr.
MSR accesses are directed to a specific CPU on multi-processor
systems.
config X86_CPUID
tristate "/dev/cpu/*/cpuid - CPU information support"
help
This device gives processes access to the x86 CPUID instruction to
be executed on a specific processor. It is a character device
with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
/dev/cpu/31/cpuid.
# disable it for opteron optimized builds because it pulls in ACPI_BOOT
config X86_HT
bool
depends on SMP && !MK8
default y
config MATH_EMULATION
bool
config MCA
bool
config EISA
bool
#config X86_IO_APIC
# bool
# default n
#config X86_LOCAL_APIC
# bool
# default n
config MTRR
bool "MTRR (Memory Type Range Register) support"
---help---
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
processor access to memory ranges. This is most useful if you have
a video (VGA) card on a PCI or AGP bus. Enabling write-combining
allows bus write transfers to be combined into a larger transfer
before bursting over the PCI/AGP bus. This can increase performance
of image write operations 2.5 times or more. Saying Y here creates a
/proc/mtrr file which may be used to manipulate your processor's
MTRRs. Typically the X server should use this.
This code has a reasonably generic interface so that similar
control registers on other processors can be easily supported
as well.
Saying Y here also fixes a problem with buggy SMP BIOSes which only
set the MTRRs for the boot CPU and not for the secondary CPUs. This
can lead to all sorts of problems, so it's good to say Y here.
Just say Y here, all x86-64 machines support MTRRs.
See <file:Documentation/mtrr.txt> for more information.
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, like most personal computers, 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
machines, but will use only one CPU of a multiprocessor machine. If
you say Y here, the kernel will run on many, but not all,
singleprocessor machines. On a singleprocessor machine, the kernel
will run faster if you say N here.
If you don't know what to do here, say N.
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. On contrary it may also break your drivers and add
priority inheritance problems to your system. Don't select it if
you rely on a stable system or have slightly obscure hardware.
It's also not very well tested on x86-64 currently.
You have been warned.
Say Y here if you are feeling brave and building a kernel for a
desktop, embedded or real-time system. Say N if you are unsure.
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SMP
default off
help
SMT scheduler support improves the CPU scheduler's decision making
when dealing with Intel Pentium 4 chips with HyperThreading at a
cost of slightly increased overhead in some places. If unsure say
N here.
config K8_NUMA
bool "K8 NUMA support"
select NUMA
depends on SMP
help
Enable NUMA (Non Unified Memory Architecture) support for
AMD Opteron Multiprocessor systems. The kernel will try to allocate
memory used by a CPU on the local memory controller of the CPU
and add some more NUMA awareness to the kernel.
This code is recommended on all multiprocessor Opteron systems
and normally doesn't hurt on others.
config NUMA_EMU
bool "NUMA emulation support"
select NUMA
depends on SMP
help
Enable NUMA emulation. A flat machine will be split
into virtual nodes when booted with "numa=fake=N", where N is the
number of nodes. This is only useful for debugging.
config DISCONTIGMEM
bool
depends on NUMA
default y
config NUMA
bool
default n
config HAVE_DEC_LOCK
bool
depends on SMP
default y
# actually 64 maximum, but you need to fix the APIC code first
# to use clustered mode or whatever your big iron needs
config NR_CPUS
int "Maximum number of CPUs (2-8)"
range 2 8
depends on SMP
default "8"
help
This allows you to specify the maximum number of CPUs which this
kernel will support. The maximum supported value is 32 and the
minimum value which makes sense is 2.
This is purely to save memory - each supported CPU requires
memory in the static kernel configuration.
config GART_IOMMU
bool "IOMMU support"
depends on PCI
help
Support the K8 IOMMU. Needed to run systems with more than 4GB of memory
properly with 32-bit PCI devices that do not support DAC (Double Address
Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter.
Normally the kernel will take the right choice by itself.
If unsure, say Y.
# need this always enabled with GART_IOMMU for the VIA workaround
config SWIOTLB
bool
depends on GART_IOMMU
default y
config DUMMY_IOMMU
bool
depends on !GART_IOMMU && !SWIOTLB
default y
help
Don't use IOMMU code. This will cause problems when you have more than 4GB
of memory and any 32-bit devices. Don't turn on unless you know what you
are doing.
config X86_MCE
bool "Machine check support" if EMBEDDED
default n
help
Include a machine check error handler to report hardware errors.
This version will require the mcelog utility to decode some
machine check error logs. See
ftp://ftp.x86-64.org/pub/linux/tools/mcelog
endmenu
#
# Use the generic interrupt handling code in kernel/irq/:
#
config GENERIC_HARDIRQS
bool
default y
config GENERIC_IRQ_PROBE
bool
default y
menu "Power management options"
source kernel/power/Kconfig
source "drivers/acpi/Kconfig"
source "arch/x86_64/kernel/cpufreq/Kconfig"
endmenu
menu "Bus options (PCI etc.)"
config PCI
bool "PCI support"
# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
config PCI_DIRECT
bool
depends on PCI
default y
config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
depends on PCI
select ACPI_BOOT
config UNORDERED_IO
bool "Unordered IO mapping access"
depends on EXPERIMENTAL
help
Use unordered stores to access IO memory mappings in device drivers.
Still very experimental. When a driver works on IA64/ppc64/pa-risc it should
work with this option, but it makes the drivers behave differently
from i386. Requires that the driver writer used memory barriers
properly.
#source "drivers/pci/Kconfig"
#source "drivers/pcmcia/Kconfig"
#source "drivers/pci/hotplug/Kconfig"
endmenu
menu "Executable file formats / Emulations"
# source "fs/Kconfig.binfmt"
config IA32_EMULATION
bool "IA32 Emulation"
help
Include code to run 32-bit programs under a 64-bit kernel. You should likely
turn this on, unless you're 100% sure that you don't have any 32-bit programs
left.
config IA32_AOUT
bool "IA32 a.out support"
depends on IA32_EMULATION
help
Support old a.out binaries in the 32bit emulation.
config COMPAT
bool
depends on IA32_EMULATION
default y
config SYSVIPC_COMPAT
bool
depends on COMPAT && SYSVIPC
default y
config UID16
bool
depends on IA32_EMULATION
default y
endmenu
# source drivers/Kconfig
# source "drivers/firmware/Kconfig"
# source fs/Kconfig
#source "arch/x86_64/oprofile/Kconfig"
#source "arch/x86_64/Kconfig.debug"
# source "security/Kconfig"
# source "crypto/Kconfig"
# source "lib/Kconfig"
endmenu
@@ -0,0 +1,92 @@
#
# x86_64/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" and "archdep" for cleaning up and making dependencies 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
# 20000913 Pavel Machek <pavel@suse.cz>
# Converted for x86_64 architecture
# 20010105 Andi Kleen, add IA32 compiler.
# ....and later removed it again....
# 20050205 Jun Nakajima <jun.nakajima@intel.com>
# Modified for Xen
#
# $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $
#
# early bootup linking needs 32bit. You can either use real 32bit tools
# here or 64bit tools in 32bit mode.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
IA32_CC := $(CC) $(CPPFLAGS) -m32 -O2 -fomit-frame-pointer
IA32_LD := $(LD) -m elf_i386
IA32_AS := $(CC) $(AFLAGS) -m32 -Wa,--32 -traditional -c
IA32_OBJCOPY := $(CROSS_COMPILE)objcopy
IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E
export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
LDFLAGS := -m elf_x86_64
#LDFLAGS_vmlinux := -e stext
CHECKFLAGS += -D__x86_64__ -m64
cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
CFLAGS += $(cflags-y)
CFLAGS += -mno-red-zone
CFLAGS += -mcmodel=kernel
CFLAGS += -pipe
# this makes reading assembly source easier, but produces worse code
# actually it makes the kernel smaller too.
CFLAGS += -fno-reorder-blocks
CFLAGS += -Wno-sign-compare
ifneq ($(CONFIG_DEBUG_INFO),y)
CFLAGS += -fno-asynchronous-unwind-tables
# -fweb shrinks the kernel a bit, but the difference is very small
# it also messes up debugging, so don't use it for now.
#CFLAGS += $(call cc-option,-fweb)
endif
# -funit-at-a-time shrinks the kernel .text considerably
# unfortunately it makes reading oopses harder.
CFLAGS += $(call cc-option,-funit-at-a-time,)
head-y := arch/xen/x86_64/kernel/head.o arch/xen/x86_64/kernel/head64.o arch/xen/x86_64/kernel/init_task.o
libs-y += arch/x86_64/lib/
core-y += arch/xen/x86_64/kernel/ arch/xen/x86_64/mm/
core-$(CONFIG_IA32_EMULATION) += arch/xen/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/xen/x86_64/pci/
drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
# for clean
obj- += kernel/ mm/ pci/
xenflags-y += -Iinclude/asm-xen/asm-x86_64/mach-xen
CFLAGS += $(xenflags-y)
AFLAGS += $(xenflags-y)
prepare: include/asm-$(XENARCH)/asm_offset.h
CLEAN_FILES += include/asm-$(XENARCH)/asm_offset.h
arch/$(XENARCH)/kernel/asm-offsets.s: include/asm include/.asm-ignore \
include/linux/version.h include/config/MARKER
include/asm-$(XENARCH)/asm_offset.h: arch/xen/x86_64/kernel/asm-offsets.s
$(call filechk,gen-asm-offsets)
ln -fsn asm_offset.h include/asm-$(XENARCH)/offset.h
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,61 @@
#
# Makefile for the linux kernel.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
CFLAGS += -Iarch/$(XENARCH)/kernel
extra-y := head.o head64.o init_task.o
obj-y := process.o signal.o entry.o traps.o \
time.o ioport.o ldt.o setup.o \
x8664_ksyms.o vsyscall.o \
setup64.o e820.o irq.o early_printk.o
c-obj-y := semaphore.o i387.o sys_x86_64.o \
ptrace.o quirks.o syscall.o
obj-y += ../../i386/kernel/timers/
s-obj-y :=
#obj-$(CONFIG_X86_MCE) += mce.o
#obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/
#obj-$(CONFIG_ACPI_BOOT) += acpi/
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
#obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o
#obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
#obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o \
# genapic.o genapic_cluster.o genapic_flat.o
#obj-$(CONFIG_PM) += suspend.o
#obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
#obj-$(CONFIG_CPU_FREQ) += cpufreq/
#obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
#obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
c-obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o
#obj-$(CONFIG_SWIOTLB) += swiotlb.o
obj-$(CONFIG_KPROBES) += kprobes.o
c-obj-$(CONFIG_MODULES) += module.o
#obj-y += topology.o
c-obj-y += intel_cacheinfo.o
bootflag-y += ../../../i386/kernel/bootflag.o
cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../../i386/kernel/cpuid.o
topology-y += ../../../i386/mach-default/topology.o
swiotlb-$(CONFIG_SWIOTLB) += ../../../ia64/lib/swiotlb.o
microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../../i386/kernel/microcode.o
intel_cacheinfo-y += ../../../i386/kernel/cpu/intel_cacheinfo.o
quirks-y += ../../../i386/kernel/quirks.o
c-link := init_task.o
s-link := vsyscall.o
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)) $(patsubst %.o,$(obj)/%.S,$(s-obj-y) $(s-link)):
ln -fsn $(srctree)/arch/x86_64/kernel/$(notdir $@) $@
obj-y += $(c-obj-y) $(s-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
clean-files += $(patsubst %.o,%.S,$(s-obj-y) $(s-obj-) $(s-link))
@@ -0,0 +1,70 @@
/*
* 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/sched.h>
#include <linux/stddef.h>
#include <linux/errno.h>
#include <linux/hardirq.h>
#include <linux/suspend.h>
#include <asm/pda.h>
#include <asm/processor.h>
#include <asm/segment.h>
#include <asm/thread_info.h>
#include <asm/ia32.h>
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define BLANK() asm volatile("\n->" : : )
int main(void)
{
#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry))
ENTRY(state);
ENTRY(flags);
ENTRY(thread);
ENTRY(pid);
BLANK();
#undef ENTRY
#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry))
ENTRY(flags);
ENTRY(addr_limit);
ENTRY(preempt_count);
BLANK();
#undef ENTRY
#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry))
ENTRY(kernelstack);
ENTRY(oldrsp);
ENTRY(pcurrent);
ENTRY(irqrsp);
ENTRY(irqcount);
ENTRY(cpunumber);
ENTRY(irqstackptr);
ENTRY(kernel_mode);
BLANK();
#undef ENTRY
#ifdef CONFIG_IA32_EMULATION
#define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry))
ENTRY(eax);
ENTRY(ebx);
ENTRY(ecx);
ENTRY(edx);
ENTRY(esi);
ENTRY(edi);
ENTRY(ebp);
ENTRY(esp);
ENTRY(eip);
BLANK();
#undef ENTRY
DEFINE(IA32_RT_SIGFRAME_sigcontext,
offsetof (struct rt_sigframe32, uc.uc_mcontext));
BLANK();
#endif
DEFINE(SIZEOF_PBE, sizeof(struct pbe));
DEFINE(pbe_address, offsetof(struct pbe, address));
DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
return 0;
}
@@ -0,0 +1,533 @@
/*
* Handle the memory map.
* The functions here do the job until bootmem takes over.
* $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <asm/page.h>
#include <asm/e820.h>
#include <asm/proto.h>
#include <asm/bootsetup.h>
/*
* PFN of last memory page.
*/
unsigned long end_pfn;
unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;
unsigned long end_pfn_map;
/*
* Add a memory region to the kernel e820 map.
*/
void __init add_memory_region(unsigned long start, unsigned long size, int type)
{
int x = e820.nr_map;
if (x == E820MAX) {
printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
return;
}
e820.map[x].addr = start;
e820.map[x].size = size;
e820.map[x].type = type;
e820.nr_map++;
}
#if 0
extern char _end[];
/*
* end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
* The direct mapping extends to end_pfn_map, so that we can directly access
* apertures, ACPI and other tables without having to play with fixmaps.
*/
/*
* Last pfn which the user wants to use.
*/
extern struct resource code_resource, data_resource;
/* Check for some hardcoded bad areas that early boot is not allowed to touch */
static inline int bad_addr(unsigned long *addrp, unsigned long size)
{
unsigned long addr = *addrp, last = addr + size;
/* various gunk below that needed for SMP startup */
if (addr < 0x8000) {
*addrp = 0x8000;
return 1;
}
/* direct mapping tables of the kernel */
if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) {
*addrp = table_end << PAGE_SHIFT;
return 1;
}
/* initrd */
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE && INITRD_START && last >= INITRD_START &&
addr < INITRD_START+INITRD_SIZE) {
*addrp = INITRD_START + INITRD_SIZE;
return 1;
}
#endif
/* kernel code + 640k memory hole (later should not be needed, but
be paranoid for now) */
if (last >= 640*1024 && addr < __pa_symbol(&_end)) {
*addrp = __pa_symbol(&_end);
return 1;
}
/* XXX ramdisk image here? */
return 0;
}
int __init e820_mapped(unsigned long start, unsigned long end, unsigned type)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
if (type && ei->type != type)
continue;
if (ei->addr >= end || ei->addr + ei->size < start)
continue;
return 1;
}
return 0;
}
/*
* Find a free area in a specific range.
*/
unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
unsigned long addr = ei->addr, last;
if (ei->type != E820_RAM)
continue;
if (addr < start)
addr = start;
if (addr > ei->addr + ei->size)
continue;
while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size)
;
last = addr + size;
if (last > ei->addr + ei->size)
continue;
if (last > end)
continue;
return addr;
}
return -1UL;
}
/*
* Free bootmem based on the e820 table for a node.
*/
void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
unsigned long last, addr;
if (ei->type != E820_RAM ||
ei->addr+ei->size <= start ||
ei->addr > end)
continue;
addr = round_up(ei->addr, PAGE_SIZE);
if (addr < start)
addr = start;
last = round_down(ei->addr + ei->size, PAGE_SIZE);
if (last >= end)
last = end;
if (last > addr && last-addr >= PAGE_SIZE)
free_bootmem_node(pgdat, addr, last-addr);
}
}
/*
* Find the highest page frame number we have available
*/
unsigned long __init e820_end_of_ram(void)
{
int i;
unsigned long end_pfn = 0;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
unsigned long start, end;
start = round_up(ei->addr, PAGE_SIZE);
end = round_down(ei->addr + ei->size, PAGE_SIZE);
if (start >= end)
continue;
if (ei->type == E820_RAM) {
if (end > end_pfn<<PAGE_SHIFT)
end_pfn = end>>PAGE_SHIFT;
} else {
if (end > end_pfn_map<<PAGE_SHIFT)
end_pfn_map = end>>PAGE_SHIFT;
}
}
if (end_pfn > end_pfn_map)
end_pfn_map = end_pfn;
if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
end_pfn_map = MAXMEM>>PAGE_SHIFT;
if (end_pfn > end_user_pfn)
end_pfn = end_user_pfn;
if (end_pfn > end_pfn_map)
end_pfn = end_pfn_map;
return end_pfn;
}
/*
* Mark e820 reserved areas as busy for the resource manager.
*/
void __init e820_reserve_resources(void)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct resource *res;
if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
continue;
res = alloc_bootmem_low(sizeof(struct resource));
switch (e820.map[i].type) {
case E820_RAM: res->name = "System RAM"; break;
case E820_ACPI: res->name = "ACPI Tables"; break;
case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
default: res->name = "reserved";
}
res->start = e820.map[i].addr;
res->end = res->start + e820.map[i].size - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
request_resource(&iomem_resource, res);
if (e820.map[i].type == E820_RAM) {
/*
* We don't know which RAM region contains kernel data,
* so we try it repeatedly and let the resource manager
* test it.
*/
request_resource(res, &code_resource);
request_resource(res, &data_resource);
}
}
}
void __init e820_print_map(char *who)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
printk(" %s: %016Lx - %016Lx ", who,
(unsigned long long) e820.map[i].addr,
(unsigned long long) (e820.map[i].addr + e820.map[i].size));
switch (e820.map[i].type) {
case E820_RAM: printk("(usable)\n");
break;
case E820_RESERVED:
printk("(reserved)\n");
break;
case E820_ACPI:
printk("(ACPI data)\n");
break;
case E820_NVS:
printk("(ACPI NVS)\n");
break;
default: printk("type %u\n", e820.map[i].type);
break;
}
}
}
/*
* Sanitize the BIOS e820 map.
*
* Some e820 responses include overlapping entries. The following
* replaces the original e820 map with a new one, removing overlaps.
*
*/
static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
{
struct change_member {
struct e820entry *pbios; /* pointer to original bios entry */
unsigned long long addr; /* address for this change point */
};
static struct change_member change_point_list[2*E820MAX] __initdata;
static struct change_member *change_point[2*E820MAX] __initdata;
static struct e820entry *overlap_list[E820MAX] __initdata;
static struct e820entry new_bios[E820MAX] __initdata;
struct change_member *change_tmp;
unsigned long current_type, last_type;
unsigned long long last_addr;
int chgidx, still_changing;
int overlap_entries;
int new_bios_entry;
int old_nr, new_nr;
int i;
/*
Visually we're performing the following (1,2,3,4 = memory types)...
Sample memory map (w/overlaps):
____22__________________
______________________4_
____1111________________
_44_____________________
11111111________________
____________________33__
___________44___________
__________33333_________
______________22________
___________________2222_
_________111111111______
_____________________11_
_________________4______
Sanitized equivalent (no overlap):
1_______________________
_44_____________________
___1____________________
____22__________________
______11________________
_________1______________
__________3_____________
___________44___________
_____________33_________
_______________2________
________________1_______
_________________4______
___________________2____
____________________33__
______________________4_
*/
/* if there's only one memory region, don't bother */
if (*pnr_map < 2)
return -1;
old_nr = *pnr_map;
/* bail out if we find any unreasonable addresses in bios map */
for (i=0; i<old_nr; i++)
if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
return -1;
/* create pointers for initial change-point information (for sorting) */
for (i=0; i < 2*old_nr; i++)
change_point[i] = &change_point_list[i];
/* record all known change-points (starting and ending addresses) */
chgidx = 0;
for (i=0; i < old_nr; i++) {
change_point[chgidx]->addr = biosmap[i].addr;
change_point[chgidx++]->pbios = &biosmap[i];
change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
change_point[chgidx++]->pbios = &biosmap[i];
}
/* sort change-point list by memory addresses (low -> high) */
still_changing = 1;
while (still_changing) {
still_changing = 0;
for (i=1; i < 2*old_nr; i++) {
/* if <current_addr> > <last_addr>, swap */
/* or, if current=<start_addr> & last=<end_addr>, swap */
if ((change_point[i]->addr < change_point[i-1]->addr) ||
((change_point[i]->addr == change_point[i-1]->addr) &&
(change_point[i]->addr == change_point[i]->pbios->addr) &&
(change_point[i-1]->addr != change_point[i-1]->pbios->addr))
)
{
change_tmp = change_point[i];
change_point[i] = change_point[i-1];
change_point[i-1] = change_tmp;
still_changing=1;
}
}
}
/* create a new bios memory map, removing overlaps */
overlap_entries=0; /* number of entries in the overlap table */
new_bios_entry=0; /* index for creating new bios map entries */
last_type = 0; /* start with undefined memory type */
last_addr = 0; /* start with 0 as last starting address */
/* loop through change-points, determining affect on the new bios map */
for (chgidx=0; chgidx < 2*old_nr; chgidx++)
{
/* keep track of all overlapping bios entries */
if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
{
/* add map entry to overlap list (> 1 entry implies an overlap) */
overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
}
else
{
/* remove entry from list (order independent, so swap with last) */
for (i=0; i<overlap_entries; i++)
{
if (overlap_list[i] == change_point[chgidx]->pbios)
overlap_list[i] = overlap_list[overlap_entries-1];
}
overlap_entries--;
}
/* if there are overlapping entries, decide which "type" to use */
/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
current_type = 0;
for (i=0; i<overlap_entries; i++)
if (overlap_list[i]->type > current_type)
current_type = overlap_list[i]->type;
/* continue building up new bios map based on this information */
if (current_type != last_type) {
if (last_type != 0) {
new_bios[new_bios_entry].size =
change_point[chgidx]->addr - last_addr;
/* move forward only if the new size was non-zero */
if (new_bios[new_bios_entry].size != 0)
if (++new_bios_entry >= E820MAX)
break; /* no more space left for new bios entries */
}
if (current_type != 0) {
new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
new_bios[new_bios_entry].type = current_type;
last_addr=change_point[chgidx]->addr;
}
last_type = current_type;
}
}
new_nr = new_bios_entry; /* retain count for new bios entries */
/* copy new bios mapping into original location */
memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
*pnr_map = new_nr;
return 0;
}
/*
* Copy the BIOS e820 map into a safe place.
*
* Sanity-check it while we're at it..
*
* If we're lucky and live on a modern system, the setup code
* will have given us a memory map that we can use to properly
* set up memory. If we aren't, we'll fake a memory map.
*
* We check to see that the memory map contains at least 2 elements
* before we'll use it, because the detection code in setup.S may
* not be perfect and most every PC known to man has two memory
* regions: one from 0 to 640k, and one from 1mb up. (The IBM
* thinkpad 560x, for example, does not cooperate with the memory
* detection code.)
*/
static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
{
/* Only one memory region (or negative)? Ignore it */
if (nr_map < 2)
return -1;
do {
unsigned long start = biosmap->addr;
unsigned long size = biosmap->size;
unsigned long end = start + size;
unsigned long type = biosmap->type;
/* Overflow in 64 bits? Ignore the memory map. */
if (start > end)
return -1;
/*
* Some BIOSes claim RAM in the 640k - 1M region.
* Not right. Fix it up.
*
* This should be removed on Hammer which is supposed to not
* have non e820 covered ISA mappings there, but I had some strange
* problems so it stays for now. -AK
*/
if (type == E820_RAM) {
if (start < 0x100000ULL && end > 0xA0000ULL) {
if (start < 0xA0000ULL)
add_memory_region(start, 0xA0000ULL-start, type);
if (end <= 0x100000ULL)
continue;
start = 0x100000ULL;
size = end - start;
}
}
add_memory_region(start, size, type);
} while (biosmap++,--nr_map);
return 0;
}
void __init setup_memory_region(void)
{
char *who = "BIOS-e820";
/*
* Try to copy the BIOS-supplied E820-map.
*
* Otherwise fake a memory map; one section from 0k->640k,
* the next section from 1mb->appropriate_mem_k
*/
sanitize_e820_map(E820_MAP, &E820_MAP_NR);
if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
unsigned long mem_size;
/* compare results from other methods and take the greater */
if (ALT_MEM_K < EXT_MEM_K) {
mem_size = EXT_MEM_K;
who = "BIOS-88";
} else {
mem_size = ALT_MEM_K;
who = "BIOS-e801";
}
e820.nr_map = 0;
add_memory_region(0, LOWMEMSIZE(), E820_RAM);
add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
}
printk(KERN_INFO "BIOS-provided physical RAM map:\n");
e820_print_map(who);
}
#endif
extern unsigned long xen_override_max_pfn;
void __init parse_memopt(char *p, char **from)
{
/*
* mem=XXX[kKmM] limits kernel memory to XXX+1MB
*
* It would be more logical to count from 0 instead of from
* HIGH_MEMORY, but we keep that for now for i386 compatibility.
*
* No support for custom mapping like i386. The reason is
* that we need to read the e820 map anyways to handle the
* ACPI mappings in the direct map. Also on x86-64 there
* should be always a good e820 map. This is only an upper
* limit, you cannot force usage of memory not in e820.
*
* -AK
*/
end_user_pfn = memparse(p, from) + HIGH_MEMORY;
end_user_pfn >>= PAGE_SHIFT;
xen_override_max_pfn = (unsigned long) end_user_pfn;
}
@@ -0,0 +1,240 @@
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm/processor.h>
/* Simple VGA output */
#ifdef __i386__
#define VGABASE (__ISA_IO_base + 0xb8000)
#else
#define VGABASE ((void __iomem *)0xffffffff800b8000UL)
#endif
#define MAX_YPOS 25
#define MAX_XPOS 80
#if 0
static int current_ypos = 1, current_xpos = 0;
static void early_vga_write(struct console *con, const char *str, unsigned n)
{
char c;
int i, k, j;
while ((c = *str++) != '\0' && n-- > 0) {
if (current_ypos >= MAX_YPOS) {
/* scroll 1 line up */
for (k = 1, j = 0; k < MAX_YPOS; k++, j++) {
for (i = 0; i < MAX_XPOS; i++) {
writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
VGABASE + 2*(MAX_XPOS*j + i));
}
}
for (i = 0; i < MAX_XPOS; i++)
writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
current_ypos = MAX_YPOS-1;
}
if (c == '\n') {
current_xpos = 0;
current_ypos++;
} else if (c != '\r') {
writew(((0x7 << 8) | (unsigned short) c),
VGABASE + 2*(MAX_XPOS*current_ypos +
current_xpos++));
if (current_xpos >= MAX_XPOS) {
current_xpos = 0;
current_ypos++;
}
}
}
}
static struct console early_vga_console = {
.name = "earlyvga",
.write = early_vga_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
#endif
/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
int early_serial_base = 0x3f8; /* ttyS0 */
#define XMTRDY 0x20
#define DLAB 0x80
#define TXR 0 /* Transmit register (WRITE) */
#define RXR 0 /* Receive register (READ) */
#define IER 1 /* Interrupt Enable */
#define IIR 2 /* Interrupt ID */
#define FCR 2 /* FIFO control */
#define LCR 3 /* Line control */
#define MCR 4 /* Modem control */
#define LSR 5 /* Line Status */
#define MSR 6 /* Modem Status */
#define DLL 0 /* Divisor Latch Low */
#define DLH 1 /* Divisor latch High */
#if 0
static int early_serial_putc(unsigned char ch)
{
unsigned timeout = 0xffff;
while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
cpu_relax();
outb(ch, early_serial_base + TXR);
return timeout ? 0 : -1;
}
static void early_serial_write(struct console *con, const char *s, unsigned n)
{
while (*s && n-- > 0) {
early_serial_putc(*s);
if (*s == '\n')
early_serial_putc('\r');
s++;
}
}
#endif
#define DEFAULT_BAUD 9600
#if 0
static __init void early_serial_init(char *s)
{
unsigned char c;
unsigned divisor;
unsigned baud = DEFAULT_BAUD;
char *e;
if (*s == ',')
++s;
if (*s) {
unsigned port;
if (!strncmp(s,"0x",2)) {
early_serial_base = simple_strtoul(s, &e, 16);
} else {
static int bases[] = { 0x3f8, 0x2f8 };
if (!strncmp(s,"ttyS",4))
s += 4;
port = simple_strtoul(s, &e, 10);
if (port > 1 || s == e)
port = 0;
early_serial_base = bases[port];
}
s += strcspn(s, ",");
if (*s == ',')
s++;
}
outb(0x3, early_serial_base + LCR); /* 8n1 */
outb(0, early_serial_base + IER); /* no interrupt */
outb(0, early_serial_base + FCR); /* no fifo */
outb(0x3, early_serial_base + MCR); /* DTR + RTS */
if (*s) {
baud = simple_strtoul(s, &e, 0);
if (baud == 0 || s == e)
baud = DEFAULT_BAUD;
}
divisor = 115200 / baud;
c = inb(early_serial_base + LCR);
outb(c | DLAB, early_serial_base + LCR);
outb(divisor & 0xff, early_serial_base + DLL);
outb((divisor >> 8) & 0xff, early_serial_base + DLH);
outb(c & ~DLAB, early_serial_base + LCR);
}
static struct console early_serial_console = {
.name = "earlyser",
.write = early_serial_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
#endif
static void xen_console_write(struct console *con, const char *s, unsigned n)
{
HYPERVISOR_console_io(CONSOLEIO_write, n, (char *) s);
}
static struct console xen_console = {
.name = "xen",
.write = xen_console_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
/* Direct interface for emergencies */
struct console *early_console = &xen_console;
/* struct console *early_console = &early_vga_console; */
static int early_console_initialized = 0;
void early_printk(const char *fmt, ...)
{
char buf[512];
int n;
va_list ap;
va_start(ap,fmt);
n = vscnprintf(buf,512,fmt,ap);
early_console->write(early_console,buf,n);
va_end(ap);
}
static int keep_early;
int __init setup_early_printk(char *opt)
{
early_console = &xen_console;
#if 0
if (early_console_initialized)
return -1;
opt = strchr(opt, '=') + 1;
strlcpy(buf,opt,sizeof(buf));
space = strchr(buf, ' ');
if (space)
*space = 0;
if (strstr(buf,"keep"))
keep_early = 1;
if (!strncmp(buf, "serial", 6)) {
early_serial_init(buf + 6);
early_console = &early_serial_console;
} else if (!strncmp(buf, "ttyS", 4)) {
early_serial_init(buf);
early_console = &early_serial_console;
} else if (!strncmp(buf, "vga", 3)) {
early_console = &early_vga_console;
}
#endif
early_console_initialized = 1;
register_console(early_console);
return 0;
}
void __init disable_early_printk(void)
{
if (!early_console_initialized || !early_console)
return;
if (!keep_early) {
printk("disabling early console\n");
unregister_console(early_console);
early_console_initialized = 0;
} else {
printk("keeping early console\n");
}
}
__setup("earlyprintk=", setup_early_printk);
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,207 @@
/*
* linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
* Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
* Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
* Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
*
* $Id: head.S,v 1.49 2002/03/19 17:39:25 ak Exp $
*
* Jun Nakajima <jun.nakajima@intel.com>
* Modified for Xen
*/
#include <linux/linkage.h>
.section __xen_guest
.ascii "GUEST_OS=linux,GUEST_VER=2.6,XEN_VER=3.0,VIRT_BASE=0xffffffff80100000"
.ascii ",LOADER=generic"
/* .ascii ",PT_MODE_WRITABLE" */
.byte 0
#include <linux/threads.h>
#include <asm/desc.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/msr.h>
#include <asm/cache.h>
/* #include <asm/thread_info.h> */
/* we are not able to switch in one step to the final KERNEL ADRESS SPACE
* because we need identity-mapped pages on setup so define __START_KERNEL to
* 0x100000 for this stage
*
*/
.text
.code64
ENTRY(_start)
cld
movq init_rsp(%rip),%rsp
/* Copy the necessary stuff from xen_start_info structure. */
movq $xen_start_info_union,%rdi
movq $64,%rcx /* sizeof (union xen_start_info_union) / sizeof (long) */
rep movsq
#ifdef CONFIG_SMP
ENTRY(startup_64_smp)
cld
#endif /* CONFIG_SMP */
/* zero EFLAGS after setting rsp */
pushq $0
popfq
movq initial_code(%rip),%rax
jmp *%rax
/* SMP bootup changes these two */
.globl initial_code
initial_code:
.quad x86_64_start_kernel
.globl init_rsp
init_rsp:
.quad init_thread_union+THREAD_SIZE-8
ENTRY(early_idt_handler)
xorl %eax,%eax
movq 8(%rsp),%rsi # get rip
movq (%rsp),%rdx
leaq early_idt_msg(%rip),%rdi
1: hlt # generate #GP
jmp 1b
early_idt_msg:
.asciz "PANIC: early exception rip %lx error %lx cr2 %lx\n"
#if 0
ENTRY(lgdt_finish)
movl $(__USER_DS),%eax # DS/ES contains default USER segment
movw %ax,%ds
movw %ax,%es
movl $(__KERNEL_DS),%eax
movw %ax,%ss # after changing gdt.
popq %rax # get the retrun address
pushq $(__KERNEL_CS)
pushq %rax
lretq
#endif
ENTRY(stext)
ENTRY(_stext)
/*
* This default setting generates an ident mapping at address 0x100000
* and a mapping for the kernel that precisely maps virtual address
* 0xffffffff80000000 to physical address 0x000000. (always using
* 2Mbyte large pages provided by PAE mode)
*/
.org 0x1000
ENTRY(init_level4_pgt)
.fill 512,8,0
/*
* We update two pgd entries to make kernel and user pgd consistent
* at pgd_populate(). It can be used for kernel modules. So we place
* this page here for those cases to avoid memory corruption.
* We also use this page to establish the initiali mapping for
* vsyscall area.
*/
.org 0x2000
ENTRY(init_level4_user_pgt)
.fill 512,8,0
/*
* This is used for vsyscall area mapping as we have a different
* level4 page table for user.
*/
.org 0x3000
ENTRY(level3_user_pgt)
.fill 512,8,0
.org 0x4000
ENTRY(cpu_gdt_table)
/* The TLS descriptors are currently at a different place compared to i386.
Hopefully nobody expects them at a fixed place (Wine?) */
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x008ffa000000ffff /* __KERNEL_COMPAT32_CS */
.quad 0x00affa000000ffff /* __KERNEL_CS */
.quad 0x00cff2000000ffff /* __KERNEL_DS */
.quad 0x00cffa000000ffff /* __USER32_CS */
.quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */
.quad 0x00affa000000ffff /* __USER_CS */
.quad 0x00cffa000000ffff /* __KERNEL32_CS */
.quad 0,0 /* TSS */
.quad 0 /* LDT */
.quad 0,0,0 /* three TLS descriptors */
.quad 0 /* unused now */
gdt_end:
/* asm/segment.h:GDT_ENTRIES must match this */
/* This should be a multiple of the cache line size */
/* GDTs of other CPUs: */
.fill (GDT_SIZE * NR_CPUS) - (gdt_end - cpu_gdt_table)
.org 0x5000
ENTRY(empty_zero_page)
.org 0x6000
ENTRY(empty_bad_page)
.org 0x7000
ENTRY(empty_bad_pte_table)
.org 0x8000
ENTRY(empty_bad_pmd_table)
.org 0x9000
#ifdef CONFIG_ACPI_SLEEP
ENTRY(wakeup_level4_pgt)
.quad 0x0000000000102007 /* -> level3_ident_pgt */
.fill 255,8,0
.quad 0x000000000010a007
.fill 254,8,0
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
.quad 0x0000000000103007 /* -> level3_kernel_pgt */
#endif
.data
.align 16
.globl cpu_gdt_descr
cpu_gdt_descr:
.word gdt_end-cpu_gdt_table
gdt:
.quad cpu_gdt_table
#ifdef CONFIG_SMP
.rept NR_CPUS-1
.word 0
.quad 0
.endr
#endif
ENTRY(gdt_table32)
.quad 0x0000000000000000 /* This one is magic */
.quad 0x0000000000000000 /* unused */
.quad 0x00af9a000000ffff /* __KERNEL_CS */
gdt32_end:
/* We need valid kernel segments for data and code in long mode too
* IRET will check the segment types kkeil 2000/10/28
* Also sysret mandates a special GDT layout
*/
#if 0
.align L1_CACHE_BYTES
#endif
.align L1_CACHE_BYTES
ENTRY(idt_table)
.rept 256
.quad 0
.quad 0
.endr
@@ -0,0 +1,132 @@
/*
* linux/arch/x86_64/kernel/head64.c -- prepare to run common code
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
*
* $Id: head64.c,v 1.22 2001/07/06 14:28:20 ak Exp $
*
* Jun Nakajima <jun.nakajima@intel.com>
* Modified for Xen.
*/
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/percpu.h>
#include <asm/processor.h>
#include <asm/proto.h>
#include <asm/smp.h>
#include <asm/bootsetup.h>
#include <asm/setup.h>
#include <asm/desc.h>
unsigned long start_pfn;
/* Don't add a printk in there. printk relies on the PDA which is not initialized
yet. */
#if 0
static void __init clear_bss(void)
{
extern char __bss_start[], __bss_end[];
memset(__bss_start, 0,
(unsigned long) __bss_end - (unsigned long) __bss_start);
}
#endif
extern char x86_boot_params[2048];
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
#define OLD_CL_MAGIC_ADDR 0x90020
#define OLD_CL_MAGIC 0xA33F
#define OLD_CL_BASE_ADDR 0x90000
#define OLD_CL_OFFSET 0x90022
extern char saved_command_line[];
#if 0
static void __init copy_bootdata(char *real_mode_data)
{
int new_data;
char * command_line;
memcpy(x86_boot_params, real_mode_data, 2048);
new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
if (!new_data) {
if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
printk("so old bootloader that it does not support commandline?!\n");
return;
}
new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
printk("old bootloader convention, maybe loadlin?\n");
}
command_line = (char *) ((u64)(new_data));
memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
printk("Bootdata ok (command line is %s)\n", saved_command_line);
}
#endif
static void __init setup_boot_cpu_data(void)
{
int dummy, eax;
/* get vendor info */
cpuid(0, &boot_cpu_data.cpuid_level,
(int *)&boot_cpu_data.x86_vendor_id[0],
(int *)&boot_cpu_data.x86_vendor_id[8],
(int *)&boot_cpu_data.x86_vendor_id[4]);
/* get cpu type */
cpuid(1, &eax, &dummy, &dummy,
(unsigned int *) &boot_cpu_data.x86_capability);
boot_cpu_data.x86 = (eax >> 8) & 0xf;
boot_cpu_data.x86_model = (eax >> 4) & 0xf;
boot_cpu_data.x86_mask = eax & 0xf;
}
extern char _end[];
void __init x86_64_start_kernel(char * real_mode_data)
{
int i;
phys_to_machine_mapping = (u32 *)xen_start_info.mfn_list;
start_pfn = (__pa(xen_start_info.pt_base) >> PAGE_SHIFT) + xen_start_info.nr_pt_frames;
for (i = 0; i < 256; i++)
set_intr_gate(i, early_idt_handler);
#if 0
asm volatile("lidt %0" :: "m" (idt_descr));
#endif
pda_init(0);
/* copy_bootdata(real_mode_data); */
#ifdef CONFIG_SMP
cpu_set(0, cpu_online_map);
#endif
/* default console: */
if (!strstr(saved_command_line, "console="))
strcat(saved_command_line, " console=tty0");
#if 0
s = strstr(saved_command_line, "earlyprintk=");
if (s != NULL)
setup_early_printk(s);
#endif
#ifdef CONFIG_DISCONTIGMEM
s = strstr(saved_command_line, "numa=");
if (s != NULL)
numa_setup(s+5);
#endif
#ifdef CONFIG_X86_IO_APIC
if (strstr(saved_command_line, "disableapic"))
disable_apic = 1;
#endif
/* You need early console to see that */
if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE)
panic("Kernel too big for kernel mapping\n");
setup_boot_cpu_data();
start_kernel();
}
@@ -0,0 +1,49 @@
#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);
struct mm_struct init_mm = INIT_MM(init_mm);
EXPORT_SYMBOL(init_mm);
/*
* Initial task structure.
*
* We need to make sure that this is 8192-byte 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);
/*
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
* no more per-task TSS's. The TSS size is kept cacheline-aligned
* so they are allowed to end up in the .data.cacheline_aligned
* section. Since TSS's are completely CPU-local, we want them
* on exact cacheline boundaries, to eliminate cacheline ping-pong.
*/
DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp;
#define ALIGN_TO_4K __attribute__((section(".data.init_task")))
@@ -0,0 +1,69 @@
/*
* linux/arch/x86_64/kernel/ioport.c
*
* This contains the io-permission bitmap code - written by obz, with changes
* by Linus.
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/thread_info.h>
#include <asm-xen/xen-public/dom0_ops.h>
/*
* sys_iopl has to be used when you want to access the IO ports
* beyond the 0x3ff range: to get the full 65536 ports bitmapped
* you'd need 8kB of bitmaps/process, which is a bit excessive.
*
*/
// asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs)
asmlinkage long sys_iopl(unsigned int new_io_pl)
{
unsigned int old_io_pl = current->thread.io_pl;
dom0_op_t op;
if (new_io_pl > 3)
return -EINVAL;
/* Trying to gain more privileges? */
if (new_io_pl > old_io_pl) {
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
}
if (!(xen_start_info.flags & SIF_PRIVILEGED))
return -EPERM;
/* Maintain OS privileges even if user attempts to relinquish them. */
if (new_io_pl == 0)
new_io_pl = 1;
/* Change our version of the privilege levels. */
current->thread.io_pl = new_io_pl;
/* Force the change at ring 0. */
op.cmd = DOM0_IOPL;
op.u.iopl.domain = DOMID_SELF;
op.u.iopl.iopl = new_io_pl;
HYPERVISOR_dom0_op(&op);
return 0;
}
/*
* this changes the io permissions bitmap in the current task.
*/
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
return turn_on ? sys_iopl(3) : 0;
}
@@ -0,0 +1,105 @@
/*
* linux/arch/x86_64/kernel/irq.c
*
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
* This file contains the lowest level x86_64-specific interrupt
* entry and irq statistics code. All the remaining irq logic is
* done by the generic kernel/irq/ code and in the
* x86_64-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>
/*
* Interrupt statistics:
*/
atomic_t irq_err_count;
/*
* Generic, controller-independent functions:
*/
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 (j=0; j<NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "CPU%d ",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 (j=0; j<NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "%10u ",
kstat_cpu(j).irqs[i]);
#endif
seq_printf(p, " %14s", irq_desc[i].handler->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 (j = 0; j < NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "%10u ", cpu_pda[j].__nmi_count);
seq_putc(p, '\n');
#ifdef CONFIG_X86_LOCAL_APIC
seq_printf(p, "LOC: ");
for (j = 0; j < NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "%10u ", cpu_pda[j].apic_timer_irqs);
seq_putc(p, '\n');
#endif
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
#ifdef CONFIG_X86_IO_APIC
#ifdef APIC_MISMATCH_DEBUG
seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
#endif
#endif
}
return 0;
}
/*
* do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
* handlers).
*/
asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
{
/* high bits used in ret_from_ code */
int irq = regs->orig_rax & __IRQ_MASK(HARDIRQ_BITS);
irq_enter();
__do_IRQ(irq, regs);
irq_exit();
return 1;
}
@@ -0,0 +1,273 @@
/*
* linux/arch/x86_64/kernel/ldt.c
*
* Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2002 Andi Kleen
*
* This handles calls from both 32bit and 64bit mode.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/ldt.h>
#include <asm/desc.h>
#include <asm/proto.h>
#include <asm/pgalloc.h>
#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
static void flush_ldt(void *null)
{
if (current->active_mm) {
load_LDT(&current->active_mm->context);
flush_page_update_queue();
}
}
#endif
static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
{
void *oldldt;
void *newldt;
unsigned oldsize;
if (mincount <= (unsigned)pc->size)
return 0;
oldsize = pc->size;
mincount = (mincount+511)&(~511);
if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
else
newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
if (!newldt)
return -ENOMEM;
if (oldsize)
memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
oldldt = pc->ldt;
memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
wmb();
pc->ldt = newldt;
wmb();
pc->size = mincount;
wmb();
if (reload) {
#ifdef CONFIG_SMP
cpumask_t mask;
preempt_disable();
#endif
make_pages_readonly(pc->ldt, (pc->size * LDT_ENTRY_SIZE) /
PAGE_SIZE);
load_LDT(pc);
flush_page_update_queue();
#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();
#else
load_LDT(pc);
#endif
}
if (oldsize) {
make_pages_writable(oldldt, (oldsize * LDT_ENTRY_SIZE) /
PAGE_SIZE);
flush_page_update_queue();
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);
flush_page_update_queue();
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;
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;
}
/*
*
* Don't touch the LDT register - we're already in the next thread.
*/
void destroy_context(struct mm_struct *mm)
{
if (mm->context.size) {
if (mm == current->active_mm)
clear_LDT();
make_pages_writable(mm->context.ldt,
(mm->context.size * LDT_ENTRY_SIZE) /
PAGE_SIZE);
flush_page_update_queue();
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)
{
/* Arbitrary number */
/* x86-64 default LDT is all zeros */
if (bytecount > 128)
bytecount = 128;
if (clear_user(ptr, bytecount))
return -EFAULT;
return bytecount;
}
static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
{
struct task_struct *me = current;
struct mm_struct * mm = me->mm;
unsigned long entry = 0, *lp;
unsigned long mach_lp;
int error;
struct user_desc ldt_info;
error = -EINVAL;
if (bytecount != sizeof(ldt_info))
goto out;
error = -EFAULT;
if (copy_from_user(&ldt_info, ptr, bytecount))
goto out;
error = -EINVAL;
if (ldt_info.entry_number >= LDT_ENTRIES)
goto out;
if (ldt_info.contents == 3) {
if (oldmode)
goto out;
if (ldt_info.seg_not_present == 0)
goto out;
}
down(&mm->context.sem);
if (ldt_info.entry_number >= (unsigned)mm->context.size) {
error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
if (error < 0)
goto out_unlock;
}
lp = (unsigned long *)((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
mach_lp = arbitrary_virt_to_machine(lp);
/* Allow LDTs to be cleared by the user. */
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
if (oldmode || LDT_empty(&ldt_info)) {
entry = 0;
goto install;
}
}
#if 0
entry = LDT_entry(&ldt_info);
#endif
if (oldmode)
entry &= ~(1 << 20);
/* Install the new entry ... */
install:
error = HYPERVISOR_update_descriptor(mach_lp, entry);
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;
}
@@ -0,0 +1,284 @@
/*
* Dynamic DMA mapping support.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm-xen/balloon.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define pte_offset_kernel pte_offset
#define pud_t pgd_t
#define pud_offset(d, va) d
#endif
/* Map a set of buffers described by scatterlist in streaming
* mode for DMA. This is the scatter-gather version of the
* above pci_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 pci_map_single are
* the same here.
*/
int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
int nents, int direction)
{
int i;
BUG_ON(direction == DMA_NONE);
for (i = 0; i < nents; i++ ) {
struct scatterlist *s = &sg[i];
BUG_ON(!s->page);
s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
s->dma_length = s->length;
}
return nents;
}
EXPORT_SYMBOL(dma_map_sg);
/* Unmap a set of streaming mode DMA translations.
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nents, int dir)
{
int i;
for (i = 0; i < nents; i++) {
struct scatterlist *s = &sg[i];
BUG_ON(s->page == NULL);
BUG_ON(s->dma_address == 0);
dma_unmap_single(dev, s->dma_address, s->dma_length, dir);
}
}
struct dma_coherent_mem {
void *virt_base;
u32 device_base;
int size;
int flags;
unsigned long *bitmap;
};
static void
xen_contig_memory(unsigned long vstart, unsigned int order)
{
/*
* Ensure multi-page extents are contiguous in machine memory.
* This code could be cleaned up some, and the number of
* hypercalls reduced.
*/
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
unsigned long pfn, i, flags;
scrub_pages(vstart, 1 << order);
balloon_lock(flags);
/* 1. Zap current PTEs, giving away the underlying pages. */
for (i = 0; i < (1<<order); i++) {
pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
pfn = pte->pte >> PAGE_SHIFT;
queue_l1_entry_update(pte, 0);
phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] =
(u32)INVALID_P2M_ENTRY;
flush_page_update_queue();
if (HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
&pfn, 1, 0) != 1) BUG();
}
/* 2. Get a new contiguous memory extent. */
if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
&pfn, 1, order) != 1) BUG();
/* 3. Map the new extent in place of old pages. */
for (i = 0; i < (1<<order); i++) {
pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
queue_l1_entry_update(
pte, ((pfn+i)<<PAGE_SHIFT)|__PAGE_KERNEL);
queue_machphys_update(
pfn+i, (__pa(vstart)>>PAGE_SHIFT)+i);
phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] =
pfn+i;
}
/* Flush updates through and flush the TLB. */
xen_tlb_flush();
balloon_unlock(flags);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
#else
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, unsigned gfp)
#endif
{
void *ret;
unsigned int order = get_order(size);
unsigned long vstart;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
int gfp = GFP_ATOMIC;
if (hwdev == NULL || ((u32)hwdev->dma_mask < 0xffffffff))
gfp |= GFP_DMA;
#else
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
/* 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;
#endif
vstart = __get_free_pages(gfp, order);
ret = (void *)vstart;
if (ret == NULL)
return ret;
xen_contig_memory(vstart, order);
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
return ret;
}
EXPORT_SYMBOL(dma_alloc_coherent);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long)vaddr, get_order(size));
}
#else
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
free_pages((unsigned long)vaddr, order);
}
EXPORT_SYMBOL(dma_free_coherent);
#if 0
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
#endif
@@ -0,0 +1,96 @@
/* Fallback functions when the main IOMMU code is not compiled in. This
code is roughly equivalent to i386. */
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <asm/proto.h>
#include <asm/processor.h>
int iommu_merge = 0;
EXPORT_SYMBOL(iommu_merge);
dma_addr_t bad_dma_address;
EXPORT_SYMBOL(bad_dma_address);
int iommu_bio_merge = 0;
EXPORT_SYMBOL(iommu_bio_merge);
int iommu_sac_force = 0;
EXPORT_SYMBOL(iommu_sac_force);
#if 0
/*
* Dummy IO MMU functions
*/
void *dma_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, unsigned gfp)
{
void *ret;
u64 mask;
int order = get_order(size);
if (hwdev)
mask = hwdev->coherent_dma_mask & *hwdev->dma_mask;
else
mask = 0xffffffff;
for (;;) {
ret = (void *)__get_free_pages(gfp, order);
if (ret == NULL)
return NULL;
*dma_handle = virt_to_bus(ret);
if ((*dma_handle & ~mask) == 0)
break;
free_pages((unsigned long)ret, order);
if (gfp & GFP_DMA)
return NULL;
gfp |= GFP_DMA;
}
memset(ret, 0, size);
return ret;
}
EXPORT_SYMBOL(dma_alloc_coherent);
void dma_free_coherent(struct device *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long)vaddr, get_order(size));
}
EXPORT_SYMBOL(dma_free_coherent);
#endif
int dma_supported(struct device *hwdev, u64 mask)
{
/*
* we fall back to GFP_DMA when the mask isn't all 1s,
* so we can't guarantee allocations that must be
* within a tighter range than GFP_DMA..
* RED-PEN this won't work for pci_map_single. Caller has to
* use GFP_DMA in the first place.
*/
if (mask < 0x00ffffff)
return 0;
return 1;
}
EXPORT_SYMBOL(dma_supported);
int dma_get_cache_alignment(void)
{
return boot_cpu_data.x86_clflush_size;
}
EXPORT_SYMBOL(dma_get_cache_alignment);
static int __init check_ram(void)
{
if (end_pfn >= 0xffffffff>>PAGE_SHIFT) {
printk(
KERN_ERR "WARNING more than 4GB of memory but IOMMU not compiled in.\n"
KERN_ERR "WARNING 32bit PCI may malfunction.\n");
}
return 0;
}
__initcall(check_ram);
@@ -0,0 +1,716 @@
/*
* linux/arch/x86-64/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*
* X86-64 port
* Andi Kleen.
*
* $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $
*
* Jun Nakajima <jun.nakajima@intel.com>
* Modified for Xen
*/
/*
* This file handles the architecture-dependent parts of process handling..
*/
#include <stdarg.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/elfcore.h>
#include <linux/smp.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/module.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/ptrace.h>
#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/mmu_context.h>
#include <asm/pda.h>
#include <asm/prctl.h>
#include <asm/kdebug.h>
#include <asm-xen/multicall.h>
#include <asm-xen/xen-public/dom0_ops.h>
#include <asm/desc.h>
#include <asm/proto.h>
#include <asm/hardirq.h>
#include <asm/ia32.h>
asmlinkage extern void ret_from_fork(void);
unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
atomic_t hlt_counter = ATOMIC_INIT(0);
unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override);
/*
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
static cpumask_t cpu_idle_map;
void disable_hlt(void)
{
atomic_inc(&hlt_counter);
}
EXPORT_SYMBOL(disable_hlt);
void enable_hlt(void)
{
atomic_dec(&hlt_counter);
}
EXPORT_SYMBOL(enable_hlt);
/* XXX XEN doesn't use default_idle(), poll_idle(). Use xen_idle() instead. */
extern int set_timeout_timer(void);
void xen_idle(void)
{
int cpu;
cpu = smp_processor_id();
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, 0);
if (need_resched()) {
local_irq_enable();
} else if (set_timeout_timer() == 0) {
/* NB. Blocking reenable events in a race-free manner. */
HYPERVISOR_block();
} else {
local_irq_enable();
HYPERVISOR_yield();
}
set_need_resched();
}
/*
* 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();
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
if (cpu_isset(cpu, cpu_idle_map))
cpu_clear(cpu, cpu_idle_map);
rmb();
__IRQ_STAT(cpu,idle_timestamp) = jiffies;
xen_idle();
}
schedule();
}
}
/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */
/* Always use xen_idle() instead. */
void __init select_idle_routine(const struct cpuinfo_x86 *c) {}
/* Prints also some state that isn't saved in the pt_regs */
void __show_regs(struct pt_regs * regs)
{
unsigned long fs, gs, shadowgs;
unsigned int fsindex,gsindex;
unsigned int ds,cs,es;
printk("\n");
print_modules();
printk("Pid: %d, comm: %.20s %s %s\n",
current->pid, current->comm, print_tainted(), system_utsname.release);
printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
printk_address(regs->rip);
printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
regs->rax, regs->rbx, regs->rcx);
printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
regs->rdx, regs->rsi, regs->rdi);
printk("RBP: %016lx R08: %016lx R09: %016lx\n",
regs->rbp, regs->r8, regs->r9);
printk("R10: %016lx R11: %016lx R12: %016lx\n",
regs->r10, regs->r11, regs->r12);
printk("R13: %016lx R14: %016lx R15: %016lx\n",
regs->r13, regs->r14, regs->r15);
asm("movl %%ds,%0" : "=r" (ds));
asm("movl %%cs,%0" : "=r" (cs));
asm("movl %%es,%0" : "=r" (es));
asm("movl %%fs,%0" : "=r" (fsindex));
asm("movl %%gs,%0" : "=r" (gsindex));
rdmsrl(MSR_FS_BASE, fs);
rdmsrl(MSR_GS_BASE, gs);
rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
printk("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
fs,fsindex,gs,gsindex,shadowgs);
printk("CS: %04x DS: %04x ES: %04x\n", cs, ds, es);
}
void show_regs(struct pt_regs *regs)
{
__show_regs(regs);
show_trace(&regs->rsp);
}
/*
* Free current thread data structures etc..
*/
void exit_thread(void)
{
struct task_struct *me = current;
struct thread_struct *t = &me->thread;
if (me->thread.io_bitmap_ptr) {
struct tss_struct *tss = &per_cpu(init_tss, get_cpu());
kfree(t->io_bitmap_ptr);
t->io_bitmap_ptr = NULL;
/*
* Careful, clear this in the TSS too:
*/
memset(tss->io_bitmap, 0xff, t->io_bitmap_max);
t->io_bitmap_max = 0;
put_cpu();
}
}
void load_gs_index(unsigned gs)
{
__load_gs_index(gs);
}
void flush_thread(void)
{
struct task_struct *tsk = current;
struct thread_info *t = current_thread_info();
if (t->flags & _TIF_ABI_PENDING)
t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
tsk->thread.debugreg0 = 0;
tsk->thread.debugreg1 = 0;
tsk->thread.debugreg2 = 0;
tsk->thread.debugreg3 = 0;
tsk->thread.debugreg6 = 0;
tsk->thread.debugreg7 = 0;
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
/*
* Forget coprocessor state..
*/
clear_fpu(tsk);
clear_used_math();
}
void release_thread(struct task_struct *dead_task)
{
if (dead_task->mm) {
if (dead_task->mm->context.size) {
printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
dead_task->comm,
dead_task->mm->context.ldt,
dead_task->mm->context.size);
BUG();
}
}
}
static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr)
{
struct user_desc ud = {
.base_addr = addr,
.limit = 0xfffff,
.seg_32bit = 1,
.limit_in_pages = 1,
.useable = 1,
};
struct n_desc_struct *desc = (void *)t->thread.tls_array;
desc += tls;
desc->a = LDT_entry_a(&ud);
desc->b = LDT_entry_b(&ud);
}
static inline u32 read_32bit_tls(struct task_struct *t, int tls)
{
struct desc_struct *desc = (void *)t->thread.tls_array;
desc += tls;
return desc->base0 |
(((u32)desc->base1) << 16) |
(((u32)desc->base2) << 24);
}
/*
* This gets called before we allocate a new thread and copy
* the current task into it.
*/
void prepare_to_copy(struct task_struct *tsk)
{
unlazy_fpu(tsk);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
unsigned long unused,
struct task_struct * p, struct pt_regs * regs)
{
int err;
struct pt_regs * childregs;
struct task_struct *me = current;
childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
*childregs = *regs;
childregs->rax = 0;
childregs->rsp = rsp;
if (rsp == ~0UL) {
childregs->rsp = (unsigned long)childregs;
}
p->thread.rsp = (unsigned long) childregs;
p->thread.rsp0 = (unsigned long) (childregs+1);
p->thread.userrsp = me->thread.userrsp;
set_ti_thread_flag(p->thread_info, TIF_FORK);
p->thread.fs = me->thread.fs;
p->thread.gs = me->thread.gs;
asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
asm("movl %%es,%0" : "=m" (p->thread.es));
asm("movl %%ds,%0" : "=m" (p->thread.ds));
if (unlikely(me->thread.io_bitmap_ptr != NULL)) {
p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
if (!p->thread.io_bitmap_ptr) {
p->thread.io_bitmap_max = 0;
return -ENOMEM;
}
memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, IO_BITMAP_BYTES);
}
/*
* Set a new TLS for the child thread?
*/
if (clone_flags & CLONE_SETTLS) {
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32))
err = ia32_child_tls(p, childregs);
else
#endif
err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8);
if (err)
goto out;
}
p->thread.io_pl = current->thread.io_pl;
err = 0;
out:
if (err && p->thread.io_bitmap_ptr) {
kfree(p->thread.io_bitmap_ptr);
p->thread.io_bitmap_max = 0;
}
return err;
}
/*
* This special macro can be used to load a debugging register
*/
#define loaddebug(thread,register) \
HYPERVISOR_set_debugreg((register), \
(thread->debugreg ## register))
/*
* switch_to(x,y) should switch tasks from x to y.
*
* This could still be optimized:
* - fold all the options into a flag word and test it with a single test.
* - could test fs/gs bitsliced
*/
struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
*next = &next_p->thread;
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
dom0_op_t op;
/* NB. No need to disable interrupts as already done in sched.c */
/* __cli(); */
// MULTICALL_flush_page_update_queue();
/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
/*
* 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);
queue_multicall0(__HYPERVISOR_fpu_taskswitch);
}
/*
* Reload esp0, LDT and the page table pointer:
*/
tss->rsp0 = next->rsp0;
// queue_multicall1(__HYPERVISOR_stack_switch, tss->rsp0);
HYPERVISOR_stack_switch(__KERNEL_DS, tss->rsp0);
/*
* Load the per-thread Thread-Local Storage descriptor.
* This is load_TLS(next, cpu) with multicalls.
*/
#define C(i) do { \
if (unlikely(next->tls_array[i] != prev->tls_array[i])) \
queue_multicall2(__HYPERVISOR_update_descriptor, \
virt_to_machine(&get_cpu_gdt_table(cpu) \
[GDT_ENTRY_TLS_MIN + i]), \
(unsigned long) &next->tls_array[i]); \
} while (0)
C(0); C(1); C(2);
#undef C
if (xen_start_info.flags & SIF_PRIVILEGED) {
op.cmd = DOM0_IOPL;
op.u.iopl.domain = DOMID_SELF;
op.u.iopl.iopl = next->io_pl;
op.interface_version = DOM0_INTERFACE_VERSION;
HYPERVISOR_dom0_op(&op);
#if 0
queue_multicall1(__HYPERVISOR_dom0_op, (unsigned long)&op);
#endif
}
/* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
// execute_multicall_list();
/* __sti(); */
/*
* Switch DS and ES.
* This won't pick up thread selector changes, but I guess that is ok.
*/
asm volatile("movl %%es,%0" : "=m" (prev->es));
if (unlikely(next->es | prev->es))
loadsegment(es, next->es);
asm volatile ("movl %%ds,%0" : "=m" (prev->ds));
if (unlikely(next->ds | prev->ds))
loadsegment(ds, next->ds);
/*
* Switch FS and GS.
*/
{
unsigned fsindex;
asm volatile("movl %%fs,%0" : "=g" (fsindex));
/* segment register != 0 always requires a reload.
also reload when it has changed.
when prev process used 64bit base always reload
to avoid an information leak. */
if (unlikely(fsindex | next->fsindex | prev->fs)) {
loadsegment(fs, next->fsindex);
/* check if the user used a selector != 0
* if yes clear 64bit base, since overloaded base
* is always mapped to the Null selector
*/
if (fsindex)
prev->fs = 0;
}
/* when next process has a 64bit base use it */
if (next->fs) {
HYPERVISOR_set_segment_base(SEGBASE_FS, next->fs);
}
prev->fsindex = fsindex;
}
{
unsigned gsindex;
asm volatile("movl %%gs,%0" : "=g" (gsindex));
if (unlikely(gsindex | next->gsindex | prev->gs)) {
load_gs_index(next->gsindex);
if (gsindex)
prev->gs = 0;
}
if (next->gs)
HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs);
prev->gsindex = gsindex;
}
/*
* Switch the PDA context.
*/
prev->userrsp = read_pda(oldrsp);
write_pda(oldrsp, next->userrsp);
write_pda(pcurrent, next_p);
write_pda(kernelstack, (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET);
/*
* Now maybe reload the debug registers
*/
if (unlikely(next->debugreg7)) {
loaddebug(next, 0);
loaddebug(next, 1);
loaddebug(next, 2);
loaddebug(next, 3);
/* no 4 and 5 */
loaddebug(next, 6);
loaddebug(next, 7);
}
/*
* Handle the IO bitmap
*/
if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
if (next->io_bitmap_ptr)
/*
* Copy the relevant range of the IO bitmap.
* Normally this is 128 bytes or less:
*/
memcpy(tss->io_bitmap, next->io_bitmap_ptr,
max(prev->io_bitmap_max, next->io_bitmap_max));
else {
/*
* Clear any possible leftover bits:
*/
memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
}
}
return prev_p;
}
/*
* sys_execve() executes a new program.
*/
asmlinkage
long sys_execve(char __user *name, char __user * __user *argv,
char __user * __user *envp, struct pt_regs regs)
{
long error;
char * filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
error = do_execve(filename, argv, envp, &regs);
if (error == 0) {
task_lock(current);
current->ptrace &= ~PT_DTRACE;
task_unlock(current);
}
putname(filename);
return error;
}
void set_personality_64bit(void)
{
/* inherit personality from parent */
/* Make sure to be in 64bit mode */
clear_thread_flag(TIF_IA32);
/* TBD: overwrites user setup. Should have two bits.
But 64bit processes have always behaved this way,
so it's not too bad. The main problem is just that
32bit childs are affected again. */
current->personality &= ~READ_IMPLIES_EXEC;
}
asmlinkage long sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL);
}
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!newsp)
newsp = regs->rsp;
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
/*
* This is trivial, and on the face of it looks like it
* could equally well be done in user mode.
*
* Not so, for quite unobvious reasons - register pressure.
* In user mode vfork() cannot have a stack frame, and if
* done by calling the "clone()" system call directly, you
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
asmlinkage long sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0,
NULL, NULL);
}
unsigned long get_wchan(struct task_struct *p)
{
unsigned long stack;
u64 fp,rip;
int count = 0;
if (!p || p == current || p->state==TASK_RUNNING)
return 0;
stack = (unsigned long)p->thread_info;
if (p->thread.rsp < stack || p->thread.rsp > stack+THREAD_SIZE)
return 0;
fp = *(u64 *)(p->thread.rsp);
do {
if (fp < (unsigned long)stack || fp > (unsigned long)stack+THREAD_SIZE)
return 0;
rip = *(u64 *)(fp+8);
if (!in_sched_functions(rip))
return rip;
fp = *(u64 *)fp;
} while (count++ < 16);
return 0;
}
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
{
int ret = 0;
int doit = task == current;
int cpu;
switch (code) {
case ARCH_SET_GS:
if (addr >= TASK_SIZE)
return -EPERM;
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
switch. */
if (addr <= 0xffffffff) {
set_32bit_tls(task, GS_TLS, addr);
if (doit) {
load_TLS(&task->thread, cpu);
load_gs_index(GS_TLS_SEL);
}
task->thread.gsindex = GS_TLS_SEL;
task->thread.gs = 0;
} else {
task->thread.gsindex = 0;
task->thread.gs = addr;
if (doit) {
load_gs_index(0);
ret = HYPERVISOR_set_segment_base(SEGBASE_GS_USER, addr);
printk("do_arch_prctl: SET_SET: addr = %lx\n", addr);
}
}
put_cpu();
break;
case ARCH_SET_FS:
/* Not strictly needed for fs, but do it for symmetry
with gs */
if (addr >= TASK_SIZE)
return -EPERM;
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
switch. */
if (addr <= 0xffffffff) {
set_32bit_tls(task, FS_TLS, addr);
if (doit) {
load_TLS(&task->thread, cpu);
asm volatile("movl %0,%%fs" :: "r" (FS_TLS_SEL));
}
task->thread.fsindex = FS_TLS_SEL;
task->thread.fs = 0;
} else {
task->thread.fsindex = 0;
task->thread.fs = addr;
if (doit) {
/* set the selector to 0 to not confuse
__switch_to */
asm volatile("movl %0,%%fs" :: "r" (0));
ret = HYPERVISOR_set_segment_base(SEGBASE_FS, addr);
}
}
put_cpu();
break;
case ARCH_GET_FS: {
unsigned long base;
if (task->thread.fsindex == FS_TLS_SEL)
base = read_32bit_tls(task, FS_TLS);
else if (doit) {
rdmsrl(MSR_FS_BASE, base);
printk("do_arch_prctl: GET_FS: addr = %lx\n", addr);
} else
base = task->thread.fs;
ret = put_user(base, (unsigned long __user *)addr);
break;
}
case ARCH_GET_GS: {
unsigned long base;
if (task->thread.gsindex == GS_TLS_SEL)
base = read_32bit_tls(task, GS_TLS);
else if (doit) {
rdmsrl(MSR_KERNEL_GS_BASE, base);
printk("do_arch_prctl: GET_GS: addr = %lx\n", addr);
} else
base = task->thread.gs;
ret = put_user(base, (unsigned long __user *)addr);
break;
}
default:
ret = -EINVAL;
break;
}
return ret;
}
long sys_arch_prctl(int code, unsigned long addr)
{
return do_arch_prctl(current, code, addr);
}
/*
* Capture the user space registers if the task is not running (in user space)
*/
int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
{
struct pt_regs *pp, ptregs;
pp = (struct pt_regs *)(tsk->thread.rsp0);
--pp;
ptregs = *pp;
ptregs.cs &= 0xffff;
ptregs.ss &= 0xffff;
elf_core_copy_regs(regs, &ptregs);
boot_option_idle_override = 1;
return 1;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,350 @@
/*
* X86-64 specific CPU setup.
* Copyright (C) 1995 Linus Torvalds
* Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
* See setup.c for older changelog.
* $Id: setup64.c,v 1.12 2002/03/21 10:09:17 ak Exp $
*
* Jun Nakajima <jun.nakajima@intel.com>
* Modified for Xen
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/bootmem.h>
#include <linux/bitops.h>
#include <asm/pda.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/desc.h>
#include <asm/atomic.h>
#include <asm/mmu_context.h>
#include <asm/smp.h>
#include <asm/i387.h>
#include <asm/percpu.h>
#include <asm/mtrr.h>
#include <asm/proto.h>
#include <asm/mman.h>
#include <asm/numa.h>
#include <asm-xen/hypervisor.h>
char x86_boot_params[2048] __initdata = {0,};
cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned;
extern struct task_struct init_task;
extern unsigned char __per_cpu_start[], __per_cpu_end[];
extern struct desc_ptr cpu_gdt_descr[];
struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table };
char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
unsigned long __supported_pte_mask = ~0UL;
static int do_not_nx __initdata = 0;
/* noexec=on|off
Control non executable mappings for 64bit processes.
on Enable(default)
off Disable
*/
int __init nonx_setup(char *str)
{
if (!strcmp(str, "on")) {
__supported_pte_mask |= _PAGE_NX;
do_not_nx = 0;
} else if (!strncmp(str, "off", 3)) {
do_not_nx = 1;
__supported_pte_mask &= ~_PAGE_NX;
}
return 0;
}
__setup("noexec=", nonx_setup); /* parsed early actually */
int force_personality32 = READ_IMPLIES_EXEC;
/* noexec32=on|off
Control non executable heap for 32bit processes.
To control the stack too use noexec=off
on PROT_READ does not imply PROT_EXEC for 32bit processes
off PROT_READ implies PROT_EXEC (default)
*/
static int __init nonx32_setup(char *str)
{
if (!strcmp(str, "on"))
force_personality32 &= ~READ_IMPLIES_EXEC;
else if (!strcmp(str, "off"))
force_personality32 |= READ_IMPLIES_EXEC;
return 0;
}
__setup("noexec32=", nonx32_setup);
/*
* Great future plan:
* Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
* Always point %gs to its beginning
*/
void __init setup_per_cpu_areas(void)
{
int i;
unsigned long size;
/* Copy section for each CPU (we discard the original) */
size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
#ifdef CONFIG_MODULES
if (size < PERCPU_ENOUGH_ROOM)
size = PERCPU_ENOUGH_ROOM;
#endif
for (i = 0; i < NR_CPUS; i++) {
unsigned char *ptr;
if (!NODE_DATA(cpu_to_node(i))) {
printk("cpu with no node %d, num_online_nodes %d\n",
i, num_online_nodes());
ptr = alloc_bootmem(size);
} else {
ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
}
if (!ptr)
panic("Cannot allocate cpu data for CPU %d\n", i);
cpu_pda[i].data_offset = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
}
}
void pda_init(int cpu)
{
pgd_t *old_level4 = (pgd_t *)xen_start_info.pt_base;
struct x8664_pda *pda = &cpu_pda[cpu];
/* Setup up data that may be needed in __get_free_pages early */
asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL,
(unsigned long)(cpu_pda + cpu));
pda->me = pda;
pda->cpunumber = cpu;
pda->irqcount = -1;
pda->kernelstack =
(unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE;
pda->active_mm = &init_mm;
pda->mmu_state = 0;
pda->kernel_mode = 1;
if (cpu == 0) {
memcpy((void *)init_level4_pgt,
(void *) xen_start_info.pt_base, PAGE_SIZE);
/* others are initialized in smpboot.c */
pda->pcurrent = &init_task;
pda->irqstackptr = boot_cpu_stack;
make_page_readonly(init_level4_pgt);
make_page_readonly(init_level4_user_pgt);
make_page_readonly(level3_user_pgt); /* for vsyscall stuff */
xen_pgd_pin(__pa_symbol(init_level4_user_pgt));
xen_pud_pin(__pa_symbol(level3_user_pgt));
set_pgd((pgd_t *)(init_level4_user_pgt + 511),
mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
} else {
pda->irqstackptr = (char *)
__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
if (!pda->irqstackptr)
panic("cannot allocate irqstack for cpu %d", cpu);
}
xen_pt_switch(__pa(init_level4_pgt));
xen_new_user_pt(__pa(init_level4_user_pgt));
if (cpu == 0) {
xen_pgd_unpin(__pa(old_level4));
#if 0
early_printk("__pa: %x, <machine_phys> old_level 4 %x\n",
__pa(xen_start_info.pt_base),
pfn_to_mfn(__pa(old_level4) >> PAGE_SHIFT));
#endif
// make_page_writable(old_level4);
// free_bootmem(__pa(old_level4), PAGE_SIZE);
}
pda->irqstackptr += IRQSTACKSIZE-64;
}
char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ]
__attribute__((section(".bss.page_aligned")));
/* May not be marked __init: used by software suspend */
void syscall_init(void)
{
#ifdef CONFIG_IA32_EMULATION
syscall32_cpu_init ();
#endif
}
void __init check_efer(void)
{
unsigned long efer;
/* rdmsrl(MSR_EFER, efer); */
/*
* At this point, Xen does not like the bit 63.
* So NX is not supported. Come back later.
*/
efer = 0;
if (!(efer & EFER_NX) || do_not_nx) {
__supported_pte_mask &= ~_PAGE_NX;
}
}
void __init cpu_gdt_init(struct desc_ptr *gdt_descr)
{
unsigned long frames[gdt_descr->size >> PAGE_SHIFT];
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_machine(va) >> PAGE_SHIFT;
make_page_readonly((void *)va);
}
flush_page_update_queue();
if (HYPERVISOR_set_gdt(frames, gdt_descr->size /
sizeof (struct desc_struct)))
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.
* A lot of state is already set up in PDA init.
*/
void __init cpu_init (void)
{
#ifdef CONFIG_SMP
int cpu = stack_smp_processor_id();
#else
int cpu = smp_processor_id();
#endif
struct tss_struct *t = &per_cpu(init_tss, cpu);
unsigned long v;
char *estacks = NULL;
struct task_struct *me;
int i;
/* CPU 0 is initialised in head64.c */
if (cpu != 0) {
pda_init(cpu);
} else
estacks = boot_exception_stacks;
me = current;
if (test_and_set_bit(cpu, &cpu_initialized))
panic("CPU#%d already initialized!\n", cpu);
printk("Initializing CPU#%d\n", cpu);
#if 0
clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
#endif
/*
* Initialize the per-CPU GDT with the boot GDT,
* and set up the GDT descriptor:
*/
if (cpu) {
memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE);
}
cpu_gdt_descr[cpu].size = GDT_SIZE;
cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu];
#if 0
asm volatile("lgdt %0" :: "m" (cpu_gdt_descr[cpu]));
asm volatile("lidt %0" :: "m" (idt_descr));
#endif
cpu_gdt_init(&cpu_gdt_descr[cpu]);
#if 0
memcpy(me->thread.tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8);
#endif
memcpy(me->thread.tls_array, &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN],
GDT_ENTRY_TLS_ENTRIES * 8);
/*
* Delete NT
*/
asm volatile("pushfq ; popq %%rax ; btr $14,%%rax ; pushq %%rax ; popfq" ::: "eax");
if (cpu == 0)
early_identify_cpu(&boot_cpu_data);
syscall_init();
barrier();
check_efer();
/*
* set up and load the per-CPU TSS
*/
for (v = 0; v < N_EXCEPTION_STACKS; v++) {
if (cpu) {
estacks = (char *)__get_free_pages(GFP_ATOMIC,
EXCEPTION_STACK_ORDER);
if (!estacks)
panic("Cannot allocate exception stack %ld %d\n",
v, cpu);
}
estacks += EXCEPTION_STKSZ;
t->ist[v] = (unsigned long)estacks;
}
t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
/*
* <= is required because the CPU will access up to
* 8 bits beyond the end of the IO permission bitmap.
*/
for (i = 0; i <= IO_BITMAP_LONGS; i++)
t->io_bitmap[i] = ~0UL;
atomic_inc(&init_mm.mm_count);
me->active_mm = &init_mm;
if (me->mm)
BUG();
enter_lazy_tlb(&init_mm, me);
load_LDT(&init_mm.context);
flush_page_update_queue();
#if 0
/*
* Clear all 6 debug registers:
*/
#define CD(register) HYPERVISOR_set_debugreg(register, 0)
CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
#undef CD
#endif
#if 0
fpu_init();
#endif
#ifdef CONFIG_NUMA
numa_add_cpu(cpu);
#endif
}
@@ -0,0 +1,493 @@
/*
* linux/arch/x86_64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
* 2000-2002 x86-64 support by Andi Kleen
*
* $Id: signal.c,v 1.18 2001/10/17 22:30:37 ak Exp $
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/compiler.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/proto.h>
/* #define DEBUG_SIG 1 */
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs);
void ia32_setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs);
asmlinkage long
sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
{
sigset_t saveset, newset;
/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
return -EINVAL;
if (copy_from_user(&newset, unewset, sizeof(newset)))
return -EFAULT;
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
saveset = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
#ifdef DEBUG_SIG
printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
saveset, newset, regs, regs->rip);
#endif
regs->rax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
}
}
asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs)
{
return do_sigaltstack(uss, uoss, regs->rsp);
}
/*
* Do a signal return; undo the signal stack.
*/
struct rt_sigframe
{
char *pretcode;
struct ucontext uc;
struct siginfo info;
};
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax)
{
unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
#define COPY(x) err |= __get_user(regs->x, &sc->x)
COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx);
COPY(rdx); COPY(rcx); COPY(rip);
COPY(r8);
COPY(r9);
COPY(r10);
COPY(r11);
COPY(r12);
COPY(r13);
COPY(r14);
COPY(r15);
{
unsigned int tmpflags;
err |= __get_user(tmpflags, &sc->eflags);
regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
regs->orig_rax = -1; /* disable syscall checks */
}
{
struct _fpstate __user * buf;
err |= __get_user(buf, &sc->fpstate);
if (buf) {
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
} else {
struct task_struct *me = current;
if (used_math()) {
clear_fpu(me);
clear_used_math();
}
}
}
err |= __get_user(*prax, &sc->rax);
return err;
badframe:
return 1;
}
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
unsigned long eax;
frame = (struct rt_sigframe __user *)(regs->rsp - 8);
if (verify_area(VERIFY_READ, frame, sizeof(*frame))) {
goto badframe;
}
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) {
goto badframe;
}
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) {
goto badframe;
}
#ifdef DEBUG_SIG
printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
#endif
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT)
goto badframe;
return eax;
badframe:
signal_fault(regs,frame,"sigreturn");
return 0;
}
/*
* Set up a signal frame.
*/
static inline int
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me)
{
int err = 0;
unsigned long eflags;
err |= __put_user(0, &sc->gs);
err |= __put_user(0, &sc->fs);
err |= __put_user(regs->rdi, &sc->rdi);
err |= __put_user(regs->rsi, &sc->rsi);
err |= __put_user(regs->rbp, &sc->rbp);
err |= __put_user(regs->rsp, &sc->rsp);
err |= __put_user(regs->rbx, &sc->rbx);
err |= __put_user(regs->rdx, &sc->rdx);
err |= __put_user(regs->rcx, &sc->rcx);
err |= __put_user(regs->rax, &sc->rax);
err |= __put_user(regs->r8, &sc->r8);
err |= __put_user(regs->r9, &sc->r9);
err |= __put_user(regs->r10, &sc->r10);
err |= __put_user(regs->r11, &sc->r11);
err |= __put_user(regs->r12, &sc->r12);
err |= __put_user(regs->r13, &sc->r13);
err |= __put_user(regs->r14, &sc->r14);
err |= __put_user(regs->r15, &sc->r15);
err |= __put_user(me->thread.trap_no, &sc->trapno);
err |= __put_user(me->thread.error_code, &sc->err);
err |= __put_user(regs->rip, &sc->rip);
eflags = regs->eflags;
if (current->ptrace & PT_PTRACED) {
eflags &= ~TF_MASK;
}
err |= __put_user(eflags, &sc->eflags);
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(me->thread.cr2, &sc->cr2);
return err;
}
/*
* Determine which stack to use..
*/
static void __user *
get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
{
unsigned long rsp;
/* Default to using normal stack - redzone*/
rsp = regs->rsp - 128;
/* This is the X/Open sanctioned signal stack switching. */
/* RED-PEN: redzone on that stack? */
if (ka->sa.sa_flags & SA_ONSTACK) {
if (sas_ss_flags(rsp) == 0)
rsp = current->sas_ss_sp + current->sas_ss_size;
}
return (void __user *)round_down(rsp - size, 16);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs)
{
struct rt_sigframe __user *frame;
struct _fpstate __user *fp = NULL;
int err = 0;
struct task_struct *me = current;
if (used_math()) {
fp = get_stack(ka, regs, sizeof(struct _fpstate));
frame = (void __user *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) {
goto give_sigsegv;
}
if (save_i387(fp) < 0)
err |= -1;
} else {
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
}
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
goto give_sigsegv;
}
if (ka->sa.sa_flags & SA_SIGINFO) {
err |= copy_siginfo_to_user(&frame->info, info);
if (err) {
goto give_sigsegv;
}
}
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->rsp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me);
err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
if (sizeof(*set) == 16) {
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
} else {
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
/* x86-64 should always use SA_RESTORER. */
if (ka->sa.sa_flags & SA_RESTORER) {
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
goto give_sigsegv;
}
if (err) {
goto give_sigsegv;
}
#ifdef DEBUG_SIG
printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax);
#endif
/* Set up registers for signal handler */
{
struct exec_domain *ed = current_thread_info()->exec_domain;
if (unlikely(ed && ed->signal_invmap && sig < 32))
sig = ed->signal_invmap[sig];
}
regs->rdi = sig;
/* In case the signal handler was declared without prototypes */
regs->rax = 0;
/* This also works for non SA_SIGINFO handlers because they expect the
next argument after the signal number on the stack. */
regs->rsi = (unsigned long)&frame->info;
regs->rdx = (unsigned long)&frame->uc;
regs->rip = (unsigned long) ka->sa.sa_handler;
regs->rsp = (unsigned long)frame;
set_fs(USER_DS);
if (regs->eflags & TF_MASK) {
if ((current->ptrace & (PT_PTRACED | PT_DTRACE)) == (PT_PTRACED | PT_DTRACE)) {
ptrace_notify(SIGTRAP);
} else {
regs->eflags &= ~TF_MASK;
}
}
#ifdef DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->rip, frame->pretcode);
#endif
return;
give_sigsegv:
force_sigsegv(sig, current);
}
/*
* OK, we're invoking a handler
*/
static void
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs)
{
#ifdef DEBUG_SIG
printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig,
regs->rip, regs->rsp, regs);
#endif
/* Are we from a system call? */
if ((long)regs->orig_rax >= 0) {
/* If so, check system call restarting.. */
switch (regs->rax) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->rax = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->rax = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->rax = regs->orig_rax;
regs->rip -= 2;
}
}
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32)) {
if (ka->sa.sa_flags & SA_SIGINFO)
ia32_setup_rt_frame(sig, ka, info, oldset, regs);
else
ia32_setup_frame(sig, ka, oldset, regs);
} else
#endif
setup_rt_frame(sig, ka, info, oldset, regs);
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
int do_signal(struct pt_regs *regs, sigset_t *oldset)
{
struct k_sigaction ka;
siginfo_t info;
int signr;
/*
* We want the common case to go fast, which
* is why we may in certain cases get here from
* kernel mode. Just return without doing anything
* if so.
*/
if ((regs->cs & 2) != 2) {
return 1;
}
if (try_to_freeze(0))
goto no_signal;
if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Reenable any watchpoints before delivering the
* signal to user space. The processor register will
* have been cleared if the watchpoint triggered
* inside the kernel.
*/
if (current->thread.debugreg7) {
HYPERVISOR_set_debugreg(7,
current->thread.debugreg7);
}
/* Whee! Actually deliver the signal. */
handle_signal(signr, &info, &ka, oldset, regs);
return 1;
}
no_signal:
/* Did we come from a system call? */
if ((long)regs->orig_rax >= 0) {
/* Restart the system call - no handlers present */
long res = regs->rax;
if (res == -ERESTARTNOHAND ||
res == -ERESTARTSYS ||
res == -ERESTARTNOINTR) {
regs->rax = regs->orig_rax;
regs->rip -= 2;
}
if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) {
regs->rax = __NR_restart_syscall;
regs->rip -= 2;
}
}
return 0;
}
void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags)
{
#ifdef DEBUG_SIG
printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n",
thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current));
#endif
/* Pending single-step? */
if (thread_info_flags & _TIF_SINGLESTEP) {
regs->eflags |= TF_MASK;
clear_thread_flag(TIF_SINGLESTEP);
}
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs,oldset);
}
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
{
struct task_struct *me = current;
if (exception_trace)
printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax);
force_sig(SIGSEGV, me);
}
@@ -0,0 +1,411 @@
/*
* Intel SMP support routines.
*
* (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
* (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
* (c) 2002,2003 Andi Kleen, SuSE Labs.
*
* This code is released under the GNU General Public License version 2 or
* later.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/interrupt.h>
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/mach_apic.h>
#include <asm/proto.h>
/*
* 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.
*/
static inline void leave_mm (unsigned long cpu)
{
if (read_pda(mmu_state) == TLBSTATE_OK)
BUG();
clear_bit(cpu, &read_pda(active_mm)->cpu_vm_mask);
__flush_tlb();
}
/*
*
* 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) clear_bit(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 superfluous
* tlb flush.
* 1a2) set cpu mmu_state to TLBSTATE_OK
* Now the smp_invalidate_interrupt won't call leave_mm if cpu0
* was in lazy tlb mode.
* 1a3) update cpu active_mm
* Now cpu0 accepts tlb flushes for the new mm.
* 1a4) set_bit(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 active_mm is correct, cpu0 already handles
* flush ipis.
* 1b1) set cpu mmu_state 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 mmu_state 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.
*/
asmlinkage void smp_invalidate_interrupt (void)
{
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 == read_pda(active_mm)) {
if (read_pda(mmu_state) == TLBSTATE_OK) {
if (flush_va == FLUSH_ALL)
local_flush_tlb();
else
__flush_tlb_one(flush_va);
} else
leave_mm(cpu);
}
ack_APIC_irq();
cpu_clear(cpu, flush_cpumask);
out:
put_cpu_no_resched();
}
static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
unsigned long va)
{
cpumask_t tmp;
/*
* A couple of (to be removed) sanity checks:
*
* - we do not send IPIs to not-yet booted CPUs.
* - current CPU must not be in mask
* - mask must exist :)
*/
BUG_ON(cpus_empty(cpumask));
cpus_and(tmp, cpumask, cpu_online_map);
BUG_ON(!cpus_equal(tmp, cpumask));
BUG_ON(cpu_isset(smp_processor_id(), cpumask));
if (!mm)
BUG();
/*
* 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;
cpus_or(flush_cpumask, cpumask, flush_cpumask);
/*
* We have to send the IPI only to
* CPUs affected.
*/
send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
while (!cpus_empty(flush_cpumask))
mb(); /* nothing. lockup detection does not belong here */;
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();
}
static void do_flush_tlb_all(void* info)
{
unsigned long cpu = smp_processor_id();
__flush_tlb_all();
if (read_pda(mmu_state) == TLBSTATE_LAZY)
leave_mm(cpu);
}
void flush_tlb_all(void)
{
on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
}
void smp_kdb_stop(void)
{
send_IPI_allbutself(KDB_VECTOR);
}
/*
* 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)
{
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;
};
static struct call_data_struct * call_data;
/*
* this function sends a 'generic call function' IPI to all other CPUs
* in the system.
*/
static void __smp_call_function (void (*func) (void *info), void *info,
int nonatomic, int wait)
{
struct call_data_struct data;
int cpus = num_online_cpus()-1;
if (!cpus)
return;
data.func = func;
data.info = info;
atomic_set(&data.started, 0);
data.wait = wait;
if (wait)
atomic_set(&data.finished, 0);
call_data = &data;
wmb();
/* 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)
cpu_relax();
if (!wait)
return;
while (atomic_read(&data.finished) != cpus)
cpu_relax();
}
/*
* 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.
* Actually there are a few legal cases, like panic.
*/
int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
int wait)
{
spin_lock(&call_lock);
__smp_call_function(func,info,nonatomic,wait);
spin_unlock(&call_lock);
return 0;
}
void smp_stop_cpu(void)
{
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
local_irq_disable();
disable_local_APIC();
local_irq_enable();
}
static void smp_really_stop_cpu(void *dummy)
{
smp_stop_cpu();
for (;;)
asm("hlt");
}
void smp_send_stop(void)
{
int nolock = 0;
if (reboot_force)
return;
/* Don't deadlock on the call lock in panic */
if (!spin_trylock(&call_lock)) {
/* ignore locking because we have paniced anyways */
nolock = 1;
}
__smp_call_function(smp_really_stop_cpu, NULL, 0, 0);
if (!nolock)
spin_unlock(&call_lock);
smp_stop_cpu();
}
/*
* Reschedule call back. Nothing to do,
* all the work is done automatically when
* we return from the interrupt.
*/
asmlinkage void smp_reschedule_interrupt(void)
{
ack_APIC_irq();
}
asmlinkage void smp_call_function_interrupt(void)
{
void (*func) (void *info) = call_data->func;
void *info = call_data->info;
int wait = call_data->wait;
ack_APIC_irq();
/*
* 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);
}
}
@@ -0,0 +1,958 @@
/*
* x86 SMP booting functions
*
* (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
* (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
* Copyright 2001 Andi Kleen, SuSE Labs.
*
* Much of the core SMP work is based on previous work by Thomas Radke, to
* whom a great many thanks are extended.
*
* Thanks to Intel for making available several different Pentium,
* Pentium Pro and Pentium-II/Xeon MP machines.
* Original development of Linux SMP code supported by Caldera.
*
* This code is released under the GNU General Public License version 2 or
* later.
*
* Fixes
* Felix Koop : NR_CPUS used properly
* Jose Renau : Handle single CPU case.
* Alan Cox : By repeated request 8) - Total BogoMIP report.
* Greg Wright : Fix for kernel stacks panic.
* Erich Boleyn : MP v1.4 and additional changes.
* Matthias Sattler : Changes for 2.1 kernel map.
* Michel Lespinasse : Changes for 2.1 kernel map.
* Michael Chastain : Change trampoline.S to gnu as.
* Alan Cox : Dumb bug: 'B' step PPro's are fine
* Ingo Molnar : Added APIC timers, based on code
* from Jose Renau
* Ingo Molnar : various cleanups and rewrites
* Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
* Maciej W. Rozycki : Bits for genuine 82489DX APICs
* Andi Kleen : Changed for SMP boot into long mode.
* Rusty Russell : Hacked into shape for new "hotplug" boot process.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/kernel_stat.h>
#include <linux/smp_lock.h>
#include <linux/irq.h>
#include <linux/bootmem.h>
#include <linux/thread_info.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/desc.h>
#include <asm/kdebug.h>
#include <asm/tlbflush.h>
#include <asm/proto.h>
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
/* Package ID of each logical CPU */
u8 phys_proc_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
EXPORT_SYMBOL(phys_proc_id);
/* Bitmask of currently online CPUs */
cpumask_t cpu_online_map;
cpumask_t cpu_callin_map;
cpumask_t cpu_callout_map;
static cpumask_t smp_commenced_mask;
/* Per CPU bogomips and other parameters */
struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
/* Set when the idlers are all forked */
int smp_threads_ready;
cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
/*
* Trampoline 80x86 program as an array.
*/
extern unsigned char trampoline_data [];
extern unsigned char trampoline_end [];
/*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
* has made sure it's suitably aligned.
*/
static unsigned long __init setup_trampoline(void)
{
void *tramp = __va(SMP_TRAMPOLINE_BASE);
extern volatile __u32 tramp_gdt_ptr;
tramp_gdt_ptr = __pa_symbol(&cpu_gdt_table);
memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
return virt_to_phys(tramp);
}
/*
* The bootstrap kernel entry code has set these up. Save them for
* a given CPU
*/
static void __init smp_store_cpu_info(int id)
{
struct cpuinfo_x86 *c = cpu_data + id;
*c = boot_cpu_data;
identify_cpu(c);
}
/*
* TSC synchronization.
*
* We first check whether all CPUs have their TSC's synchronized,
* then we print a warning if not, and always resync.
*/
static atomic_t tsc_start_flag = ATOMIC_INIT(0);
static atomic_t tsc_count_start = ATOMIC_INIT(0);
static atomic_t tsc_count_stop = ATOMIC_INIT(0);
static unsigned long long tsc_values[NR_CPUS];
#define NR_LOOPS 5
extern unsigned int fast_gettimeoffset_quotient;
static void __init synchronize_tsc_bp (void)
{
int i;
unsigned long long t0;
unsigned long long sum, avg;
long long delta;
long one_usec;
int buggy = 0;
printk(KERN_INFO "checking TSC synchronization across %u CPUs: ",num_booting_cpus());
one_usec = cpu_khz;
atomic_set(&tsc_start_flag, 1);
wmb();
/*
* We loop a few times to get a primed instruction cache,
* then the last pass is more or less synchronized and
* the BP and APs set their cycle counters to zero all at
* once. This reduces the chance of having random offsets
* between the processors, and guarantees that the maximum
* delay between the cycle counters is never bigger than
* the latency of information-passing (cachelines) between
* two CPUs.
*/
for (i = 0; i < NR_LOOPS; i++) {
/*
* all APs synchronize but they loop on '== num_cpus'
*/
while (atomic_read(&tsc_count_start) != num_booting_cpus()-1) mb();
atomic_set(&tsc_count_stop, 0);
wmb();
/*
* this lets the APs save their current TSC:
*/
atomic_inc(&tsc_count_start);
sync_core();
rdtscll(tsc_values[smp_processor_id()]);
/*
* We clear the TSC in the last loop:
*/
if (i == NR_LOOPS-1)
write_tsc(0, 0);
/*
* Wait for all APs to leave the synchronization point:
*/
while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1) mb();
atomic_set(&tsc_count_start, 0);
wmb();
atomic_inc(&tsc_count_stop);
}
sum = 0;
for (i = 0; i < NR_CPUS; i++) {
if (cpu_isset(i, cpu_callout_map)) {
t0 = tsc_values[i];
sum += t0;
}
}
avg = sum / num_booting_cpus();
sum = 0;
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_isset(i, cpu_callout_map))
continue;
delta = tsc_values[i] - avg;
if (delta < 0)
delta = -delta;
/*
* We report bigger than 2 microseconds clock differences.
*/
if (delta > 2*one_usec) {
long realdelta;
if (!buggy) {
buggy = 1;
printk("\n");
}
realdelta = delta / one_usec;
if (tsc_values[i] < avg)
realdelta = -realdelta;
printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n",
i, realdelta);
}
sum += delta;
}
if (!buggy)
printk("passed.\n");
}
static void __init synchronize_tsc_ap (void)
{
int i;
/*
* Not every cpu is online at the time
* this gets called, so we first wait for the BP to
* finish SMP initialization:
*/
while (!atomic_read(&tsc_start_flag)) mb();
for (i = 0; i < NR_LOOPS; i++) {
atomic_inc(&tsc_count_start);
while (atomic_read(&tsc_count_start) != num_booting_cpus()) mb();
sync_core();
rdtscll(tsc_values[smp_processor_id()]);
if (i == NR_LOOPS-1)
write_tsc(0, 0);
atomic_inc(&tsc_count_stop);
while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
}
}
#undef NR_LOOPS
static atomic_t init_deasserted;
void __init smp_callin(void)
{
int cpuid, phys_id;
unsigned long timeout;
/*
* If waken up by an INIT in an 82489DX configuration
* we may get here before an INIT-deassert IPI reaches
* our local APIC. We have to wait for the IPI or we'll
* lock up on an APIC access.
*/
while (!atomic_read(&init_deasserted));
/*
* (This works even if the APIC is not enabled.)
*/
phys_id = GET_APIC_ID(apic_read(APIC_ID));
cpuid = smp_processor_id();
if (cpu_isset(cpuid, cpu_callin_map)) {
panic("smp_callin: phys CPU#%d, CPU#%d already present??\n",
phys_id, cpuid);
}
Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
/*
* STARTUP IPIs are fragile beasts as they might sometimes
* trigger some glue motherboard logic. Complete APIC bus
* silence for 1 second, this overestimates the time the
* boot CPU is spending to send the up to 2 STARTUP IPIs
* by a factor of two. This should be enough.
*/
/*
* Waiting 2s total for startup (udelay is not yet working)
*/
timeout = jiffies + 2*HZ;
while (time_before(jiffies, timeout)) {
/*
* Has the boot CPU finished it's STARTUP sequence?
*/
if (cpu_isset(cpuid, cpu_callout_map))
break;
rep_nop();
}
if (!time_before(jiffies, timeout)) {
panic("smp_callin: CPU%d started up but did not get a callout!\n",
cpuid);
}
/*
* the boot CPU has finished the init stage and is spinning
* on callin_map until we finish. We are free to set up this
* CPU, first the APIC. (this is probably redundant on most
* boards)
*/
Dprintk("CALLIN, before setup_local_APIC().\n");
setup_local_APIC();
local_irq_enable();
/*
* Get our bogomips.
*/
calibrate_delay();
Dprintk("Stack at about %p\n",&cpuid);
disable_APIC_timer();
/*
* Save our processor parameters
*/
smp_store_cpu_info(cpuid);
local_irq_disable();
/*
* Allow the master to continue.
*/
cpu_set(cpuid, cpu_callin_map);
/*
* Synchronize the TSC with the BP
*/
if (cpu_has_tsc)
synchronize_tsc_ap();
}
int cpucount;
/*
* Activate a secondary processor.
*/
void __init start_secondary(void)
{
/*
* Dont put anything before smp_callin(), SMP
* booting is too fragile that we want to limit the
* things done here to the most necessary things.
*/
cpu_init();
smp_callin();
/* otherwise gcc will move up the smp_processor_id before the cpu_init */
barrier();
Dprintk("cpu %d: waiting for commence\n", smp_processor_id());
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
rep_nop();
Dprintk("cpu %d: setting up apic clock\n", smp_processor_id());
setup_secondary_APIC_clock();
Dprintk("cpu %d: enabling apic timer\n", smp_processor_id());
if (nmi_watchdog == NMI_IO_APIC) {
disable_8259A_irq(0);
enable_NMI_through_LVT0(NULL);
enable_8259A_irq(0);
}
enable_APIC_timer();
/*
* low-memory mappings have been cleared, flush them from
* the local TLBs too.
*/
local_flush_tlb();
Dprintk("cpu %d eSetting cpu_online_map\n", smp_processor_id());
cpu_set(smp_processor_id(), cpu_online_map);
wmb();
cpu_idle();
}
extern volatile unsigned long init_rsp;
extern void (*initial_code)(void);
#if APIC_DEBUG
static inline void inquire_remote_apic(int apicid)
{
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" };
int timeout, status;
printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
printk("... APIC #%d %s: ", apicid, names[i]);
/*
* Wait for idle.
*/
apic_wait_icr_idle();
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
timeout = 0;
do {
udelay(100);
status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
switch (status) {
case APIC_ICR_RR_VALID:
status = apic_read(APIC_RRR);
printk("%08x\n", status);
break;
default:
printk("failed\n");
}
}
}
#endif
static int __init wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
{
unsigned long send_status = 0, accept_status = 0;
int maxlvt, timeout, num_starts, j;
Dprintk("Asserting INIT.\n");
/*
* Turn INIT on target chip
*/
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/*
* Send IPI
*/
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
| APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
timeout = 0;
do {
Dprintk("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
mdelay(10);
Dprintk("Deasserting INIT.\n");
/* Target chip */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/* Send IPI */
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
timeout = 0;
do {
Dprintk("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
atomic_set(&init_deasserted, 1);
/*
* Should we send STARTUP IPIs ?
*
* Determine this based on the APIC version.
* If we don't have an integrated APIC, don't send the STARTUP IPIs.
*/
if (APIC_INTEGRATED(apic_version[phys_apicid]))
num_starts = 2;
else
num_starts = 0;
/*
* Run STARTUP IPI loop.
*/
Dprintk("#startup loops: %d.\n", num_starts);
maxlvt = get_maxlvt();
for (j = 1; j <= num_starts; j++) {
Dprintk("Sending STARTUP #%d.\n",j);
apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
Dprintk("After apic_write.\n");
/*
* STARTUP IPI
*/
/* Target chip */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/* Boot on the stack */
/* Kick the second */
apic_write_around(APIC_ICR, APIC_DM_STARTUP
| (start_rip >> 12));
/*
* Give the other CPU some time to accept the IPI.
*/
udelay(300);
Dprintk("Startup point 1.\n");
Dprintk("Waiting for send to finish...\n");
timeout = 0;
do {
Dprintk("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
/*
* Give the other CPU some time to accept the IPI.
*/
udelay(200);
/*
* Due to the Pentium erratum 3AP.
*/
if (maxlvt > 3) {
apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
}
accept_status = (apic_read(APIC_ESR) & 0xEF);
if (send_status || accept_status)
break;
}
Dprintk("After Startup.\n");
if (send_status)
printk(KERN_ERR "APIC never delivered???\n");
if (accept_status)
printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
return (send_status | accept_status);
}
static void __init do_boot_cpu (int apicid)
{
struct task_struct *idle;
unsigned long boot_error;
int timeout, cpu;
unsigned long start_rip;
cpu = ++cpucount;
/*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
idle = fork_idle(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
x86_cpu_to_apicid[cpu] = apicid;
cpu_pda[cpu].pcurrent = idle;
start_rip = setup_trampoline();
init_rsp = idle->thread.rsp;
per_cpu(init_tss,cpu).rsp0 = init_rsp;
initial_code = start_secondary;
clear_ti_thread_flag(idle->thread_info, TIF_FORK);
printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid,
start_rip, init_rsp);
/*
* This grunge runs the startup process for
* the targeted processor.
*/
atomic_set(&init_deasserted, 0);
Dprintk("Setting warm reset code and vector.\n");
CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
Dprintk("1.\n");
*((volatile unsigned short *) phys_to_virt(0x469)) = start_rip >> 4;
Dprintk("2.\n");
*((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
Dprintk("3.\n");
/*
* Be paranoid about clearing APIC errors.
*/
if (APIC_INTEGRATED(apic_version[apicid])) {
apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
}
/*
* Status is now clean
*/
boot_error = 0;
/*
* Starting actual IPI sequence...
*/
boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
if (!boot_error) {
/*
* allow APs to start initializing.
*/
Dprintk("Before Callout %d.\n", cpu);
cpu_set(cpu, cpu_callout_map);
Dprintk("After Callout %d.\n", cpu);
/*
* Wait 5s total for a response
*/
for (timeout = 0; timeout < 50000; timeout++) {
if (cpu_isset(cpu, cpu_callin_map))
break; /* It has booted */
udelay(100);
}
if (cpu_isset(cpu, cpu_callin_map)) {
/* number CPUs logically, starting from 1 (BSP is 0) */
Dprintk("OK.\n");
print_cpu_info(&cpu_data[cpu]);
Dprintk("CPU has booted.\n");
} else {
boot_error = 1;
if (*((volatile unsigned char *)phys_to_virt(SMP_TRAMPOLINE_BASE))
== 0xA5)
/* trampoline started but...? */
printk("Stuck ??\n");
else
/* trampoline code not run */
printk("Not responding.\n");
#if APIC_DEBUG
inquire_remote_apic(apicid);
#endif
}
}
if (boot_error) {
cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
cpucount--;
x86_cpu_to_apicid[cpu] = BAD_APICID;
x86_cpu_to_log_apicid[cpu] = BAD_APICID;
}
}
cycles_t cacheflush_time;
unsigned long cache_decay_ticks;
static void smp_tune_scheduling (void)
{
int cachesize; /* kB */
unsigned long bandwidth = 1000; /* MB/s */
/*
* Rough estimation for SMP scheduling, this is the number of
* cycles it takes for a fully memory-limited process to flush
* the SMP-local cache.
*
* (For a P5 this pretty much means we will choose another idle
* CPU almost always at wakeup time (this is due to the small
* L1 cache), on PIIs it's around 50-100 usecs, depending on
* the cache size)
*/
if (!cpu_khz) {
/*
* this basically disables processor-affinity
* scheduling on SMP without a TSC.
*/
cacheflush_time = 0;
return;
} else {
cachesize = boot_cpu_data.x86_cache_size;
if (cachesize == -1) {
cachesize = 16; /* Pentiums, 2x8kB cache */
bandwidth = 100;
}
cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
}
cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
printk(KERN_INFO "per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
(long)cacheflush_time/(cpu_khz/1000),
((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
printk(KERN_INFO "task migration cache decay timeout: %ld msecs.\n",
(cache_decay_ticks + 1) * 1000 / HZ);
}
/*
* Cycle through the processors sending APIC IPIs to boot each.
*/
static void __init smp_boot_cpus(unsigned int max_cpus)
{
unsigned apicid, cpu, bit, kicked;
nmi_watchdog_default();
/*
* Setup boot CPU information
*/
smp_store_cpu_info(0); /* Final full version of the data */
printk(KERN_INFO "CPU%d: ", 0);
print_cpu_info(&cpu_data[0]);
current_thread_info()->cpu = 0;
smp_tune_scheduling();
if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
hard_smp_processor_id());
physid_set(hard_smp_processor_id(), phys_cpu_present_map);
}
/*
* If we couldn't find an SMP configuration at boot time,
* get out of here now!
*/
if (!smp_found_config) {
printk(KERN_NOTICE "SMP motherboard not detected.\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
phys_cpu_present_map = physid_mask_of_physid(0);
if (APIC_init_uniprocessor())
printk(KERN_NOTICE "Local APIC not detected."
" Using dummy APIC emulation.\n");
goto smp_done;
}
/*
* Should not be necessary because the MP table should list the boot
* CPU too, but we do it for the sake of robustness anyway.
*/
if (!physid_isset(boot_cpu_id, phys_cpu_present_map)) {
printk(KERN_NOTICE "weird, boot CPU (#%d) not listed by the BIOS.\n",
boot_cpu_id);
physid_set(hard_smp_processor_id(), phys_cpu_present_map);
}
/*
* If we couldn't find a local APIC, then get out of here now!
*/
if (APIC_INTEGRATED(apic_version[boot_cpu_id]) && !cpu_has_apic) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_id);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
phys_cpu_present_map = physid_mask_of_physid(0);
disable_apic = 1;
goto smp_done;
}
verify_local_APIC();
/*
* If SMP should be disabled, then really disable it!
*/
if (!max_cpus) {
smp_found_config = 0;
printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
io_apic_irqs = 0;
cpu_online_map = cpumask_of_cpu(0);
phys_cpu_present_map = physid_mask_of_physid(0);
disable_apic = 1;
goto smp_done;
}
connect_bsp_APIC();
setup_local_APIC();
if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
BUG();
x86_cpu_to_apicid[0] = boot_cpu_id;
/*
* Now scan the CPU present map and fire up the other CPUs.
*/
Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map));
kicked = 1;
for (bit = 0; kicked < NR_CPUS && bit < MAX_APICS; bit++) {
apicid = cpu_present_to_apicid(bit);
/*
* Don't even attempt to start the boot CPU!
*/
if (apicid == boot_cpu_id || (apicid == BAD_APICID))
continue;
if (!physid_isset(apicid, phys_cpu_present_map))
continue;
if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
continue;
do_boot_cpu(apicid);
++kicked;
}
/*
* Cleanup possible dangling ends...
*/
{
/*
* Install writable page 0 entry to set BIOS data area.
*/
local_flush_tlb();
/*
* Paranoid: Set warm reset code and vector here back
* to default values.
*/
CMOS_WRITE(0, 0xf);
*((volatile int *) phys_to_virt(0x467)) = 0;
}
/*
* Allow the user to impress friends.
*/
Dprintk("Before bogomips.\n");
if (!cpucount) {
printk(KERN_INFO "Only one processor found.\n");
} else {
unsigned long bogosum = 0;
for (cpu = 0; cpu < NR_CPUS; cpu++)
if (cpu_isset(cpu, cpu_callout_map))
bogosum += cpu_data[cpu].loops_per_jiffy;
printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
cpucount+1,
bogosum/(500000/HZ),
(bogosum/(5000/HZ))%100);
Dprintk("Before bogocount - setting activated=1.\n");
}
/*
* Construct cpu_sibling_map[], so that we can tell the
* sibling CPU efficiently.
*/
for (cpu = 0; cpu < NR_CPUS; cpu++)
cpus_clear(cpu_sibling_map[cpu]);
for (cpu = 0; cpu < NR_CPUS; cpu++) {
int siblings = 0;
int i;
if (!cpu_isset(cpu, cpu_callout_map))
continue;
if (smp_num_siblings > 1) {
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_isset(i, cpu_callout_map))
continue;
if (phys_proc_id[cpu] == phys_proc_id[i]) {
siblings++;
cpu_set(i, cpu_sibling_map[cpu]);
}
}
} else {
siblings++;
cpu_set(cpu, cpu_sibling_map[cpu]);
}
if (siblings != smp_num_siblings) {
printk(KERN_WARNING
"WARNING: %d siblings found for CPU%d, should be %d\n",
siblings, cpu, smp_num_siblings);
smp_num_siblings = siblings;
}
}
Dprintk("Boot done.\n");
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
*/
if (!skip_ioapic_setup && nr_ioapics)
setup_IO_APIC();
else
nr_ioapics = 0;
setup_boot_APIC_clock();
/*
* Synchronize the TSC with the AP
*/
if (cpu_has_tsc && cpucount)
synchronize_tsc_bp();
smp_done:
time_init_smp();
}
/* These are wrappers to interface to the new boot process. Someone
who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
void __init smp_prepare_cpus(unsigned int max_cpus)
{
smp_boot_cpus(max_cpus);
}
void __devinit smp_prepare_boot_cpu(void)
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callout_map);
}
int __devinit __cpu_up(unsigned int cpu)
{
/* This only works at boot for x86. See "rewrite" above. */
if (cpu_isset(cpu, smp_commenced_mask)) {
local_irq_enable();
return -ENOSYS;
}
/* In case one didn't come up */
if (!cpu_isset(cpu, cpu_callin_map)) {
local_irq_enable();
return -EIO;
}
local_irq_enable();
/* Unleash the CPU! */
Dprintk("waiting for cpu %d\n", cpu);
cpu_set(cpu, smp_commenced_mask);
while (!cpu_isset(cpu, cpu_online_map))
mb();
return 0;
}
void __init smp_cpus_done(unsigned int max_cpus)
{
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
zap_low_mappings();
}
@@ -0,0 +1,840 @@
/*
* linux/arch/i386/kernel/time.c
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*
* This file contains the PC-specific time handling details:
* reading the RTC at bootup, etc..
* 1994-07-02 Alan Modra
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
* 1995-03-26 Markus Kuhn
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
* precision CMOS clock update
* 1996-05-03 Ingo Molnar
* fixed time warps in do_[slow|fast]_gettimeoffset()
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
* "A Kernel Model for Precision Timekeeping" by Dave Mills
* 1998-09-05 (Various)
* More robust do_fast_gettimeoffset() algorithm implemented
* (works with APM, Cyrix 6x86MX and Centaur C6),
* monotonic gettimeofday() with fast_get_timeoffset(),
* drift-proof precision TSC calibration on boot
* (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
* Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
* ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
* 1998-12-16 Andrea Arcangeli
* Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
* because was not accounting lost_ticks.
* 1998-12-24 Copyright (C) 1998 Andrea Arcangeli
* Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
* serialize accesses to xtime/lost_ticks).
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/module.h>
#include <linux/sysdev.h>
#include <linux/bcd.h>
#include <linux/efi.h>
#include <linux/mca.h>
#include <linux/sysctl.h>
#include <linux/percpu.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/irq.h>
#include <asm/msr.h>
#include <asm/delay.h>
#include <asm/mpspec.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/timer.h>
#include "mach_time.h"
#include <linux/timex.h>
#include <linux/config.h>
#include <asm/hpet.h>
#include <asm/arch_hooks.h>
#include "io_ports.h"
extern spinlock_t i8259A_lock;
int pit_latch_buggy; /* extern */
u64 jiffies_64 = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
#if defined(__x86_64__)
unsigned long vxtime_hz = PIT_TICK_RATE;
struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES;
struct timespec __xtime __section_xtime;
struct timezone __sys_tz __section_sys_tz;
static inline void rdtscll_sync(unsigned long *tsc)
{
#ifdef CONFIG_SMP
sync_core();
#endif
rdtscll(*tsc);
}
#endif
u32 cpu_khz; /* Detected as we calibrate the TSC */
extern unsigned long wall_jiffies;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
extern struct init_timer_opts timer_tsc_init;
extern struct timer_opts timer_tsc;
struct timer_opts *cur_timer = &timer_tsc;
/* These are peridically updated in shared_info, and then copied here. */
u32 shadow_tsc_stamp;
u64 shadow_system_time;
static u32 shadow_time_version;
static struct timeval shadow_tv;
/*
* We use this to ensure that gettimeofday() is monotonically increasing. We
* only break this guarantee if the wall clock jumps backwards "a long way".
*/
static struct timeval last_seen_tv = {0,0};
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
/* Periodically propagate synchronised time base to the RTC and to Xen. */
static long last_rtc_update, last_update_to_xen;
#endif
/* Periodically take synchronised time base from Xen, if we need it. */
static long last_update_from_xen; /* UTC seconds when last read Xen clock. */
/* Keep track of last time we did processing/updating of jiffies and xtime. */
u64 processed_system_time; /* System time (ns) at last processing. */
DEFINE_PER_CPU(u64, processed_system_time);
#define NS_PER_TICK (1000000000ULL/HZ)
#define HANDLE_USEC_UNDERFLOW(_tv) do { \
while ((_tv).tv_usec < 0) { \
(_tv).tv_usec += USEC_PER_SEC; \
(_tv).tv_sec--; \
} \
} while (0)
#define HANDLE_USEC_OVERFLOW(_tv) do { \
while ((_tv).tv_usec >= USEC_PER_SEC) { \
(_tv).tv_usec -= USEC_PER_SEC; \
(_tv).tv_sec++; \
} \
} while (0)
static inline void __normalize_time(time_t *sec, s64 *nsec)
{
while (*nsec >= NSEC_PER_SEC) {
(*nsec) -= NSEC_PER_SEC;
(*sec)++;
}
while (*nsec < 0) {
(*nsec) += NSEC_PER_SEC;
(*sec)--;
}
}
/* Does this guest OS track Xen time, or set its wall clock independently? */
static int independent_wallclock = 0;
static int __init __independent_wallclock(char *str)
{
independent_wallclock = 1;
return 1;
}
__setup("independent_wallclock", __independent_wallclock);
#define INDEPENDENT_WALLCLOCK() \
(independent_wallclock || (xen_start_info.flags & SIF_INITDOMAIN))
/*
* Reads a consistent set of time-base values from Xen, into a shadow data
* area. Must be called with the xtime_lock held for writing.
*/
static void __get_time_values_from_xen(void)
{
shared_info_t *s = HYPERVISOR_shared_info;
do {
shadow_time_version = s->time_version2;
rmb();
shadow_tv.tv_sec = s->wc_sec;
shadow_tv.tv_usec = s->wc_usec;
shadow_tsc_stamp = (u32)s->tsc_timestamp;
shadow_system_time = s->system_time;
rmb();
}
while (shadow_time_version != s->time_version1);
cur_timer->mark_offset();
}
#define TIME_VALUES_UP_TO_DATE \
({ rmb(); (shadow_time_version == HYPERVISOR_shared_info->time_version2); })
/*
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
*/
void do_gettimeofday(struct timeval *tv)
{
unsigned long seq;
unsigned long usec, sec;
unsigned long max_ntp_tick;
unsigned long flags;
s64 nsec;
do {
unsigned long lost;
seq = read_seqbegin(&xtime_lock);
usec = cur_timer->get_offset();
lost = jiffies - wall_jiffies;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
if (unlikely(time_adjust < 0)) {
max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
usec = min(usec, max_ntp_tick);
if (lost)
usec += lost * max_ntp_tick;
}
else if (unlikely(lost))
usec += lost * (USEC_PER_SEC / HZ);
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / NSEC_PER_USEC);
nsec = shadow_system_time - processed_system_time;
__normalize_time(&sec, &nsec);
usec += (long)nsec / NSEC_PER_USEC;
if (unlikely(!TIME_VALUES_UP_TO_DATE)) {
/*
* We may have blocked for a long time,
* rendering our calculations invalid
* (e.g. the time delta may have
* overflowed). Detect that and recalculate
* with fresh values.
*/
write_seqlock_irqsave(&xtime_lock, flags);
__get_time_values_from_xen();
write_sequnlock_irqrestore(&xtime_lock, flags);
continue;
}
} while (read_seqretry(&xtime_lock, seq));
while (usec >= USEC_PER_SEC) {
usec -= USEC_PER_SEC;
sec++;
}
/* Ensure that time-of-day is monotonically increasing. */
if ((sec < last_seen_tv.tv_sec) ||
((sec == last_seen_tv.tv_sec) && (usec < last_seen_tv.tv_usec))) {
sec = last_seen_tv.tv_sec;
usec = last_seen_tv.tv_usec;
} else {
last_seen_tv.tv_sec = sec;
last_seen_tv.tv_usec = usec;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
EXPORT_SYMBOL(do_gettimeofday);
int do_settimeofday(struct timespec *tv)
{
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec;
s64 nsec;
struct timespec xentime;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
if (!INDEPENDENT_WALLCLOCK())
return 0; /* Silent failure? */
write_seqlock_irq(&xtime_lock);
/*
* Ensure we don't get blocked for a long time so that our time delta
* overflows. If that were to happen then our shadow time values would
* be stale, so we can retry with fresh ones.
*/
again:
nsec = (s64)tv->tv_nsec -
((s64)cur_timer->get_offset() * (s64)NSEC_PER_USEC);
if (unlikely(!TIME_VALUES_UP_TO_DATE)) {
__get_time_values_from_xen();
goto again;
}
__normalize_time(&sec, &nsec);
set_normalized_timespec(&xentime, sec, nsec);
/*
* This is revolting. We need to set "xtime" correctly. However, the
* value in this location is the value at the most recent update of
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
nsec -= (shadow_system_time - processed_system_time);
__normalize_time(&sec, &nsec);
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
/* Reset all our running time counts. They make no sense now. */
last_seen_tv.tv_sec = 0;
last_update_from_xen = 0;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
if (xen_start_info.flags & SIF_INITDOMAIN) {
dom0_op_t op;
last_rtc_update = last_update_to_xen = 0;
op.cmd = DOM0_SETTIME;
op.u.settime.secs = xentime.tv_sec;
op.u.settime.usecs = xentime.tv_nsec / NSEC_PER_USEC;
op.u.settime.system_time = shadow_system_time;
write_sequnlock_irq(&xtime_lock);
HYPERVISOR_dom0_op(&op);
} else
#endif
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
}
EXPORT_SYMBOL(do_settimeofday);
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
static int set_rtc_mmss(unsigned long nowtime)
{
int retval;
/* gets recalled with irq locally disabled */
spin_lock(&rtc_lock);
if (efi_enabled)
retval = efi_set_rtc_mmss(nowtime);
else
retval = mach_set_rtc_mmss(nowtime);
spin_unlock(&rtc_lock);
return retval;
}
#endif
/* monotonic_clock(): returns # of nanoseconds passed since time_init()
* Note: This function is required to return accurate
* time even in the absence of multiple timer ticks.
*/
unsigned long long monotonic_clock(void)
{
return cur_timer->monotonic_clock();
}
EXPORT_SYMBOL(monotonic_clock);
#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
unsigned long profile_pc(struct pt_regs *regs)
{
unsigned long pc = instruction_pointer(regs);
if (in_lock_functions(pc))
return *(unsigned long *)(regs->ebp + 4);
return pc;
}
EXPORT_SYMBOL(profile_pc);
#endif
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
static inline void do_timer_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
time_t wtm_sec, sec;
s64 delta, nsec;
long sec_diff, wtm_nsec;
do {
__get_time_values_from_xen();
delta = (s64)(shadow_system_time +
((s64)cur_timer->get_offset() *
(s64)NSEC_PER_USEC) -
processed_system_time);
}
while (!TIME_VALUES_UP_TO_DATE);
if (unlikely(delta < 0)) {
printk("Timer ISR: Time went backwards: %lld %lld %lld %lld\n",
delta, shadow_system_time,
((s64)cur_timer->get_offset() * (s64)NSEC_PER_USEC),
processed_system_time);
return;
}
/* Process elapsed jiffies since last call. */
while (delta >= NS_PER_TICK) {
delta -= NS_PER_TICK;
processed_system_time += NS_PER_TICK;
do_timer(regs);
update_process_times(user_mode(regs));
if (regs)
profile_tick(CPU_PROFILING, regs);
}
/*
* Take synchronised time from Xen once a minute if we're not
* synchronised ourselves, and we haven't chosen to keep an independent
* time base.
*/
if (!INDEPENDENT_WALLCLOCK() &&
((time_status & STA_UNSYNC) != 0) &&
(xtime.tv_sec > (last_update_from_xen + 60))) {
/* Adjust shadow for jiffies that haven't updated xtime yet. */
shadow_tv.tv_usec -=
(jiffies - wall_jiffies) * (USEC_PER_SEC / HZ);
HANDLE_USEC_UNDERFLOW(shadow_tv);
/*
* Reset our running time counts if they are invalidated by
* a warp backwards of more than 500ms.
*/
sec_diff = xtime.tv_sec - shadow_tv.tv_sec;
if (unlikely(abs(sec_diff) > 1) ||
unlikely(((sec_diff * USEC_PER_SEC) +
(xtime.tv_nsec / NSEC_PER_USEC) -
shadow_tv.tv_usec) > 500000)) {
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
last_rtc_update = last_update_to_xen = 0;
#endif
last_seen_tv.tv_sec = 0;
}
/* Update our unsynchronised xtime appropriately. */
sec = shadow_tv.tv_sec;
nsec = shadow_tv.tv_usec * NSEC_PER_USEC;
__normalize_time(&sec, &nsec);
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
last_update_from_xen = sec;
}
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
if (!(xen_start_info.flags & SIF_INITDOMAIN))
return;
/* Send synchronised time to Xen approximately every minute. */
if (((time_status & STA_UNSYNC) == 0) &&
(xtime.tv_sec > (last_update_to_xen + 60))) {
dom0_op_t op;
struct timeval tv;
tv.tv_sec = xtime.tv_sec;
tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
tv.tv_usec += (jiffies - wall_jiffies) * (USEC_PER_SEC/HZ);
HANDLE_USEC_OVERFLOW(tv);
op.cmd = DOM0_SETTIME;
op.u.settime.secs = tv.tv_sec;
op.u.settime.usecs = tv.tv_usec;
op.u.settime.system_time = shadow_system_time;
HYPERVISOR_dom0_op(&op);
last_update_to_xen = xtime.tv_sec;
}
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if ((time_status & STA_UNSYNC) == 0 &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000)
>= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000)
<= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
/* horrible...FIXME */
if (efi_enabled) {
if (efi_set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600;
} else if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
#endif
}
/*
* This is the same as the above, except we _also_ save the current
* Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
*/
irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*
* Here we are in the timer irq handler. We just have irqs locally
* disabled but we don't know if the timer_bh is running on the other
* CPU. We need to avoid to SMP race with it. NOTE: we don' t need
* the irq version of write_lock because as just said we have irq
* locally disabled. -arca
*/
write_seqlock(&xtime_lock);
do_timer_interrupt(irq, NULL, regs);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
/* not static: needed by APM */
unsigned long get_cmos_time(void)
{
unsigned long retval;
spin_lock(&rtc_lock);
if (efi_enabled)
retval = efi_get_time();
else
retval = mach_get_cmos_time();
spin_unlock(&rtc_lock);
return retval;
}
static long clock_cmos_diff, sleep_start;
static int timer_suspend(struct sys_device *dev, u32 state)
{
/*
* Estimate time zone so that set_time can update the clock
*/
clock_cmos_diff = -get_cmos_time();
clock_cmos_diff += get_seconds();
sleep_start = get_cmos_time();
return 0;
}
static int timer_resume(struct sys_device *dev)
{
unsigned long flags;
unsigned long sec;
unsigned long sleep_length;
#ifdef CONFIG_HPET_TIMER
if (is_hpet_enabled())
hpet_reenable();
#endif
sec = get_cmos_time() + clock_cmos_diff;
sleep_length = (get_cmos_time() - sleep_start) * HZ;
write_seqlock_irqsave(&xtime_lock, flags);
xtime.tv_sec = sec;
xtime.tv_nsec = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
jiffies += sleep_length;
wall_jiffies += sleep_length;
return 0;
}
static struct sysdev_class timer_sysclass = {
.resume = timer_resume,
.suspend = timer_suspend,
set_kset_name("timer"),
};
/* XXX this driverfs stuff should probably go elsewhere later -john */
static struct sys_device device_timer = {
.id = 0,
.cls = &timer_sysclass,
};
static int time_init_device(void)
{
int error = sysdev_class_register(&timer_sysclass);
if (!error)
error = sysdev_register(&device_timer);
return error;
}
device_initcall(time_init_device);
#ifdef CONFIG_HPET_TIMER
extern void (*late_time_init)(void);
/* Duplicate of time_init() below, with hpet_enable part added */
void __init hpet_time_init(void)
{
xtime.tv_sec = get_cmos_time();
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
if (hpet_enable() >= 0) {
printk("Using HPET for base-timer\n");
}
cur_timer = select_timer();
printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
time_init_hook();
}
#endif
/* Dynamically-mapped IRQ. */
static int TIMER_IRQ;
static struct irqaction irq_timer = {
timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer",
NULL, NULL
};
void __init time_init(void)
{
#ifdef CONFIG_HPET_TIMER
if (is_hpet_capable()) {
/*
* HPET initialization needs to do memory-mapped io. So, let
* us do a late initialization after mem_init().
*/
late_time_init = hpet_time_init;
return;
}
#endif
__get_time_values_from_xen();
xtime.tv_sec = shadow_tv.tv_sec;
xtime.tv_nsec = shadow_tv.tv_usec * NSEC_PER_USEC;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
processed_system_time = shadow_system_time;
if (timer_tsc_init.init(NULL) != 0)
BUG();
printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
#if defined(__x86_64__)
vxtime.mode = VXTIME_TSC;
vxtime.quot = (1000000L << 32) / vxtime_hz;
vxtime.tsc_quot = (1000L << 32) / cpu_khz;
vxtime.hz = vxtime_hz;
rdtscll_sync(&vxtime.last_tsc);
#endif
TIMER_IRQ = bind_virq_to_irq(VIRQ_TIMER);
(void)setup_irq(TIMER_IRQ, &irq_timer);
}
/* Convert jiffies to system time. Call with xtime_lock held for reading. */
static inline u64 __jiffies_to_st(unsigned long j)
{
return processed_system_time + ((j - jiffies) * NS_PER_TICK);
}
/*
* This function works out when the the next timer function has to be
* executed (by looking at the timer list) and sets the Xen one-shot
* domain timer to the appropriate value. This is typically called in
* cpu_idle() before the domain blocks.
*
* The function returns a non-0 value on error conditions.
*
* It must be called with interrupts disabled.
*/
int set_timeout_timer(void)
{
u64 alarm = 0;
int ret = 0;
#ifdef CONFIG_SMP
unsigned long seq;
#endif
/*
* This is safe against long blocking (since calculations are
* not based on TSC deltas). It is also safe against warped
* system time since suspend-resume is cooperative and we
* would first get locked out.
*/
#ifdef CONFIG_SMP
do {
seq = read_seqbegin(&xtime_lock);
if (smp_processor_id())
alarm = __jiffies_to_st(jiffies + 1);
else
alarm = __jiffies_to_st(jiffies + 1);
} while (read_seqretry(&xtime_lock, seq));
#else
alarm = __jiffies_to_st(next_timer_interrupt());
#endif
/* Failure is pretty bad, but we'd best soldier on. */
if ( HYPERVISOR_set_timer_op(alarm) != 0 )
ret = -1;
return ret;
}
void time_suspend(void)
{
/* nothing */
}
/* No locking required. We are only CPU running, and interrupts are off. */
void time_resume(void)
{
if (timer_tsc_init.init(NULL) != 0)
BUG();
/* Get timebases for new environment. */
__get_time_values_from_xen();
/* Reset our own concept of passage of system time. */
processed_system_time = shadow_system_time;
/* Accept a warp in UTC (wall-clock) time. */
last_seen_tv.tv_sec = 0;
/* Make sure we resync UTC time with Xen on next timer interrupt. */
last_update_from_xen = 0;
}
#ifdef CONFIG_SMP
#define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg)
static irqreturn_t local_timer_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
s64 delta;
int cpu = smp_processor_id();
do {
__get_time_values_from_xen();
delta = (s64)(shadow_system_time +
((s64)cur_timer->get_offset() *
(s64)NSEC_PER_USEC) -
per_cpu(processed_system_time, cpu));
}
while (!TIME_VALUES_UP_TO_DATE);
if (unlikely(delta < 0)) {
printk("Timer ISR/%d: Time went backwards: %lld %lld %lld %lld\n",
cpu, delta, shadow_system_time,
((s64)cur_timer->get_offset() * (s64)NSEC_PER_USEC),
processed_system_time);
return IRQ_HANDLED;
}
/* Process elapsed jiffies since last call. */
while (delta >= NS_PER_TICK) {
delta -= NS_PER_TICK;
per_cpu(processed_system_time, cpu) += NS_PER_TICK;
if (regs)
update_process_times(user_mode(regs));
#if 0
if (regs)
profile_tick(CPU_PROFILING, regs);
#endif
}
if (smp_processor_id() == 0) {
xxprint("bug bug\n");
BUG();
}
return IRQ_HANDLED;
}
static struct irqaction local_irq_timer = {
local_timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "ltimer",
NULL, NULL
};
void local_setup_timer(void)
{
int seq, time_irq;
int cpu = smp_processor_id();
do {
seq = read_seqbegin(&xtime_lock);
per_cpu(processed_system_time, cpu) = shadow_system_time;
} while (read_seqretry(&xtime_lock, seq));
time_irq = bind_virq_to_irq(VIRQ_TIMER);
(void)setup_irq(time_irq, &local_irq_timer);
}
#endif
/*
* /proc/sys/xen: This really belongs in another file. It can stay here for
* now however.
*/
static ctl_table xen_subtable[] = {
{1, "independent_wallclock", &independent_wallclock,
sizeof(independent_wallclock), 0644, NULL, proc_dointvec},
{0}
};
static ctl_table xen_table[] = {
{123, "xen", NULL, 0, 0555, xen_subtable},
{0}
};
static int __init xen_sysctl_init(void)
{
(void)register_sysctl_table(xen_table, 0);
return 0;
}
__initcall(xen_sysctl_init);
@@ -0,0 +1,973 @@
/*
* linux/arch/x86-64/traps.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*
* $Id: traps.c,v 1.36 2002/03/24 11:09:10 ak Exp $
*/
/*
* 'Traps.c' handles hardware traps and faults after we have saved some
* state in 'entry.S'.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/kdebug.h>
#include <asm/processor.h>
#include <asm/smp.h>
#include <asm/pgalloc.h>
#include <asm/pda.h>
#include <asm/proto.h>
#include <asm/nmi.h>
#include <linux/irq.h>
extern struct gate_struct idt_table[256];
asmlinkage void divide_error(void);
asmlinkage void debug(void);
asmlinkage void nmi(void);
asmlinkage void int3(void);
asmlinkage void overflow(void);
asmlinkage void bounds(void);
asmlinkage void invalid_op(void);
asmlinkage void device_not_available(void);
asmlinkage void double_fault(void);
asmlinkage void coprocessor_segment_overrun(void);
asmlinkage void invalid_TSS(void);
asmlinkage void segment_not_present(void);
asmlinkage void stack_segment(void);
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void simd_coprocessor_error(void);
asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
asmlinkage void machine_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void call_debug(void);
struct notifier_block *die_chain;
static DEFINE_SPINLOCK(die_notifier_lock);
int register_die_notifier(struct notifier_block *nb)
{
int err = 0;
unsigned long flags;
spin_lock_irqsave(&die_notifier_lock, flags);
err = notifier_chain_register(&die_chain, nb);
spin_unlock_irqrestore(&die_notifier_lock, flags);
return err;
}
static inline void conditional_sti(struct pt_regs *regs)
{
if (regs->eflags & X86_EFLAGS_IF)
local_irq_enable();
}
static int kstack_depth_to_print = 10;
#ifdef CONFIG_KALLSYMS
#include <linux/kallsyms.h>
int printk_address(unsigned long address)
{
unsigned long offset = 0, symsize;
const char *symname;
char *modname;
char *delim = ":";
char namebuf[128];
symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
if (!symname)
return printk("[<%016lx>]", address);
if (!modname)
modname = delim = "";
return printk("<%016lx>{%s%s%s%s%+ld}",
address,delim,modname,delim,symname,offset);
}
#else
int printk_address(unsigned long address)
{
return printk("[<%016lx>]", address);
}
#endif
unsigned long *in_exception_stack(int cpu, unsigned long stack)
{
int k;
for (k = 0; k < N_EXCEPTION_STACKS; k++) {
struct tss_struct *tss = &per_cpu(init_tss, cpu);
unsigned long end = tss->ist[k] + EXCEPTION_STKSZ;
if (stack >= tss->ist[k] && stack <= end)
return (unsigned long *)end;
}
return NULL;
}
/*
* x86-64 can have upto three kernel stacks:
* process stack
* interrupt stack
* severe exception (double fault, nmi, stack fault) hardware stack
* Check and process them in order.
*/
void show_trace(unsigned long *stack)
{
unsigned long addr;
unsigned long *irqstack, *irqstack_end, *estack_end;
const int cpu = safe_smp_processor_id();
int i;
printk("\nCall Trace:");
i = 0;
estack_end = in_exception_stack(cpu, (unsigned long)stack);
if (estack_end) {
while (stack < estack_end) {
addr = *stack++;
if (__kernel_text_address(addr)) {
i += printk_address(addr);
i += printk(" ");
if (i > 50) {
printk("\n");
i = 0;
}
}
}
i += printk(" <EOE> ");
i += 7;
stack = (unsigned long *) estack_end[-2];
}
irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 64);
if (stack >= irqstack && stack < irqstack_end) {
printk("<IRQ> ");
while (stack < irqstack_end) {
addr = *stack++;
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* memory, it *may* be the address of a calling
* routine; if so, print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
if (__kernel_text_address(addr)) {
i += printk_address(addr);
i += printk(" ");
if (i > 50) {
printk("\n ");
i = 0;
}
}
}
stack = (unsigned long *) (irqstack_end[-1]);
printk(" <EOI> ");
i += 7;
}
while (((long) stack & (THREAD_SIZE-1)) != 0) {
addr = *stack++;
if (__kernel_text_address(addr)) {
i += printk_address(addr);
i += printk(" ");
if (i > 50) {
printk("\n ");
i = 0;
}
}
}
printk("\n");
}
void show_stack(struct task_struct *tsk, unsigned long * rsp)
{
unsigned long *stack;
int i;
const int cpu = safe_smp_processor_id();
unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);
// debugging aid: "show_stack(NULL, NULL);" prints the
// back trace for this cpu.
if (rsp == NULL) {
if (tsk)
rsp = (unsigned long *)tsk->thread.rsp;
else
rsp = (unsigned long *)&rsp;
}
stack = rsp;
for(i=0; i < kstack_depth_to_print; i++) {
if (stack >= irqstack && stack <= irqstack_end) {
if (stack == irqstack_end) {
stack = (unsigned long *) (irqstack_end[-1]);
printk(" <EOI> ");
}
} else {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
}
if (i && ((i % 4) == 0))
printk("\n ");
printk("%016lx ", *stack++);
}
show_trace((unsigned long *)rsp);
}
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
unsigned long dummy;
show_trace(&dummy);
}
EXPORT_SYMBOL(dump_stack);
void show_registers(struct pt_regs *regs)
{
int i;
int in_kernel = (regs->cs & 3) == 0;
unsigned long rsp;
const int cpu = safe_smp_processor_id();
struct task_struct *cur = cpu_pda[cpu].pcurrent;
rsp = regs->rsp;
printk("CPU %d ", cpu);
__show_regs(regs);
printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
cur->comm, cur->pid, cur->thread_info, cur);
/*
* When in-kernel, we also print out the stack and code at the
* time of the fault..
*/
if (in_kernel) {
printk("Stack: ");
show_stack(NULL, (unsigned long*)rsp);
printk("\nCode: ");
if(regs->rip < PAGE_OFFSET)
goto bad;
for(i=0;i<20;i++)
{
unsigned char c;
if(__get_user(c, &((unsigned char*)regs->rip)[i])) {
bad:
printk(" Bad RIP value.");
break;
}
printk("%02x ", c);
}
}
printk("\n");
}
void handle_BUG(struct pt_regs *regs)
{
struct bug_frame f;
char tmp;
if (regs->cs & 3)
return;
if (__copy_from_user(&f, (struct bug_frame *) regs->rip,
sizeof(struct bug_frame)))
return;
if ((unsigned long)f.filename < __PAGE_OFFSET ||
f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
return;
if (__get_user(tmp, f.filename))
f.filename = "unmapped filename";
printk("----------- [cut here ] --------- [please bite here ] ---------\n");
printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line);
}
void out_of_line_bug(void)
{
BUG();
}
static DEFINE_SPINLOCK(die_lock);
static int die_owner = -1;
void oops_begin(void)
{
int cpu = safe_smp_processor_id();
/* racy, but better than risking deadlock. */
local_irq_disable();
if (!spin_trylock(&die_lock)) {
if (cpu == die_owner)
/* nested oops. should stop eventually */;
else
spin_lock(&die_lock);
}
die_owner = cpu;
console_verbose();
bust_spinlocks(1);
}
void oops_end(void)
{
die_owner = -1;
bust_spinlocks(0);
spin_unlock(&die_lock);
local_irq_enable(); /* make sure back scroll still works */
if (panic_on_oops)
panic("Oops");
}
void __die(const char * str, struct pt_regs * regs, long err)
{
static int die_counter;
printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
#ifdef CONFIG_PREEMPT
printk("PREEMPT ");
#endif
#ifdef CONFIG_SMP
printk("SMP ");
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
printk("DEBUG_PAGEALLOC");
#endif
printk("\n");
notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
show_registers(regs);
/* Executive summary in case the oops scrolled away */
printk(KERN_ALERT "RIP ");
printk_address(regs->rip);
printk(" RSP <%016lx>\n", regs->rsp);
}
void die(const char * str, struct pt_regs * regs, long err)
{
oops_begin();
handle_BUG(regs);
__die(str, regs, err);
oops_end();
do_exit(SIGSEGV);
}
static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
if (!(regs->eflags & VM_MASK) && (regs->cs == __KERNEL_CS))
die(str, regs, err);
}
#if 0
void die_nmi(char *str, struct pt_regs *regs)
{
oops_begin();
/*
* We are in trouble anyway, lets at least try
* to get a message out.
*/
printk(str, safe_smp_processor_id());
show_registers(regs);
if (panic_on_timeout || panic_on_oops)
panic("nmi watchdog");
printk("console shuts up ...\n");
oops_end();
do_exit(SIGSEGV);
}
#endif
static void do_trap(int trapnr, int signr, char *str,
struct pt_regs * regs, long error_code, siginfo_t *info)
{
conditional_sti(regs);
#ifdef CONFIG_CHECKING
{
unsigned long gs;
struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
printk("%s: wrong gs %lx expected %p rip %lx\n", str, gs, pda,
regs->rip);
}
}
#endif
if ((regs->cs & 3) != 0) {
struct task_struct *tsk = current;
if (exception_trace && unhandled_signal(tsk, signr))
printk(KERN_INFO
"%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid, str,
regs->rip,regs->rsp,error_code);
tsk->thread.error_code = error_code;
tsk->thread.trap_no = trapnr;
if (info)
force_sig_info(signr, info, tsk);
else
force_sig(signr, tsk);
return;
}
/* kernel trap */
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->rip);
if (fixup) {
regs->rip = fixup->fixup;
} else
die(str, regs, error_code);
return;
}
}
#define DO_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, regs, error_code, NULL); \
}
#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, regs, error_code, &info); \
}
DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->rip)
DO_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_ERROR( 5, SIGSEGV, "bounds", bounds)
DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
DO_ERROR(18, SIGSEGV, "reserved", reserved)
#define DO_ERROR_STACK(trapnr, signr, str, name) \
asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \
{ \
struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return regs; \
if (regs->cs & 3) { \
memcpy(pr, regs, sizeof(struct pt_regs)); \
regs = pr; \
} \
do_trap(trapnr, signr, str, regs, error_code, NULL); \
return regs; \
}
DO_ERROR_STACK(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR_STACK( 8, SIGSEGV, "double fault", double_fault)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
conditional_sti(regs);
#ifdef CONFIG_CHECKING
{
unsigned long gs;
struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
oops_in_progress++;
printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
oops_in_progress--;
}
}
#endif
if ((regs->cs & 3)!=0) {
struct task_struct *tsk = current;
if (exception_trace && unhandled_signal(tsk, SIGSEGV))
printk(KERN_INFO
"%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid,
regs->rip,regs->rsp,error_code);
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 13;
force_sig(SIGSEGV, tsk);
return;
}
/* kernel gp */
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->rip);
if (fixup) {
regs->rip = fixup->fixup;
return;
}
if (notify_die(DIE_GPF, "general protection fault", regs,
error_code, 13, SIGSEGV) == NOTIFY_STOP)
return;
die("general protection fault", regs, error_code);
}
}
#if 0
static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
{
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
printk("You probably have a hardware problem with your RAM chips\n");
/* Clear and disable the memory parity error line. */
reason = (reason & 0xf) | 4;
outb(reason, 0x61);
}
static void io_check_error(unsigned char reason, struct pt_regs * regs)
{
printk("NMI: IOCK error (debug interrupt?)\n");
show_registers(regs);
/* Re-enable the IOCK line, wait for a few seconds */
reason = (reason & 0xf) | 8;
outb(reason, 0x61);
mdelay(2000);
reason &= ~8;
outb(reason, 0x61);
}
static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
printk("Dazed and confused, but trying to continue\n");
printk("Do you have a strange power saving mode enabled?\n");
}
asmlinkage void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
/* Only the BSP gets external NMIs from the system. */
if (!smp_processor_id())
reason = get_nmi_reason();
if (!(reason & 0xc0)) {
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
== NOTIFY_STOP)
return;
#ifdef CONFIG_X86_LOCAL_APIC
/*
* Ok, so this is none of the documented NMI sources,
* so it must be the NMI watchdog.
*/
if (nmi_watchdog > 0) {
nmi_watchdog_tick(regs,reason);
return;
}
#endif
unknown_nmi_error(reason, regs);
return;
}
if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
return;
/* AK: following checks seem to be broken on modern chipsets. FIXME */
if (reason & 0x80)
mem_parity_error(reason, regs);
if (reason & 0x40)
io_check_error(reason, regs);
/*
* Reassert NMI in case it became active meanwhile
* as it's edge-triggered.
*/
outb(0x8f, 0x70);
inb(0x71); /* dummy */
outb(0x0f, 0x70);
inb(0x71); /* dummy */
}
#endif
asmlinkage void do_int3(struct pt_regs * regs, long error_code)
{
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
return;
}
do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
return;
}
/* runs on IST stack. */
asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
{
struct pt_regs *pr;
unsigned long condition;
struct task_struct *tsk = current;
siginfo_t info;
pr = (struct pt_regs *)(current->thread.rsp0)-1;
if (regs->cs & 3) {
memcpy(pr, regs, sizeof(struct pt_regs));
regs = pr;
}
#ifdef CONFIG_CHECKING
{
/* RED-PEN interaction with debugger - could destroy gs */
unsigned long gs;
struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
printk("debug handler: wrong gs %lx expected %p\n", gs, pda);
}
}
#endif
asm("movq %%db6,%0" : "=r" (condition));
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_STOP) {
return regs;
}
conditional_sti(regs);
/* Mask out spurious debug traps due to lazy DR7 setting */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
if (!tsk->thread.debugreg7) {
goto clear_dr7;
}
}
tsk->thread.debugreg6 = condition;
/* Mask out spurious TF errors due to lazy TF clearing */
if ((condition & DR_STEP) &&
(notify_die(DIE_DEBUGSTEP, "debugstep", regs, condition,
1, SIGTRAP) != NOTIFY_STOP)) {
/*
* The TF error should be masked out only if the current
* process is not traced and if the TRAP flag has been set
* previously by a tracing process (condition detected by
* the PT_DTRACE flag); remember that the i386 TRAP flag
* can be modified by the process itself in user mode,
* allowing programs to debug themselves without the ptrace()
* interface.
*/
if ((regs->cs & 3) == 0)
goto clear_TF_reenable;
if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
goto clear_TF;
}
/* Ok, finally something we can handle */
tsk->thread.trap_no = 1;
tsk->thread.error_code = error_code;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
if ((regs->cs & 3) == 0)
goto clear_dr7;
info.si_addr = (void __user *)regs->rip;
force_sig_info(SIGTRAP, &info, tsk);
clear_dr7:
asm volatile("movq %0,%%db7"::"r"(0UL));
notify_die(DIE_DEBUG, "debug", regs, condition, 1, SIGTRAP);
return regs;
clear_TF_reenable:
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
clear_TF:
/* RED-PEN could cause spurious errors */
if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP)
!= NOTIFY_STOP)
regs->eflags &= ~TF_MASK;
return regs;
}
static int kernel_math_error(struct pt_regs *regs, char *str)
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->rip);
if (fixup) {
regs->rip = fixup->fixup;
return 1;
}
notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE);
#if 0
/* This should be a die, but warn only for now */
die(str, regs, 0);
#else
printk(KERN_DEBUG "%s: %s at ", current->comm, str);
printk_address(regs->rip);
printk("\n");
#endif
return 0;
}
/*
* Note that we play around with the 'TS' bit in an attempt to get
* the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour
*/
asmlinkage void do_coprocessor_error(struct pt_regs *regs)
{
void __user *rip = (void __user *)(regs->rip);
struct task_struct * task;
siginfo_t info;
unsigned short cwd, swd;
conditional_sti(regs);
if ((regs->cs & 3) == 0 &&
kernel_math_error(regs, "kernel x87 math error"))
return;
/*
* Save the info for the exception handler and clear the error.
*/
task = current;
save_init_fpu(task);
task->thread.trap_no = 16;
task->thread.error_code = 0;
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = __SI_FAULT;
info.si_addr = rip;
/*
* (~cwd & swd) will mask out exceptions that are not set to unmasked
* status. 0x3f is the exception bits in these regs, 0x200 is the
* C1 reg you need in case of a stack fault, 0x040 is the stack
* fault bit. We should only be taking one exception at a time,
* so if this combination doesn't produce any single exception,
* then we have a bad program that isn't synchronizing its FPU usage
* and it will suffer the consequences since we won't be able to
* fully reproduce the context of the exception
*/
cwd = get_fpu_cwd(task);
swd = get_fpu_swd(task);
switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
case 0x000:
default:
break;
case 0x001: /* Invalid Op */
case 0x041: /* Stack Fault */
case 0x241: /* Stack Fault | Direction */
info.si_code = FPE_FLTINV;
break;
case 0x002: /* Denormalize */
case 0x010: /* Underflow */
info.si_code = FPE_FLTUND;
break;
case 0x004: /* Zero Divide */
info.si_code = FPE_FLTDIV;
break;
case 0x008: /* Overflow */
info.si_code = FPE_FLTOVF;
break;
case 0x020: /* Precision */
info.si_code = FPE_FLTRES;
break;
}
force_sig_info(SIGFPE, &info, task);
}
asmlinkage void bad_intr(void)
{
printk("bad interrupt");
}
asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
{
void __user *rip = (void __user *)(regs->rip);
struct task_struct * task;
siginfo_t info;
unsigned short mxcsr;
conditional_sti(regs);
if ((regs->cs & 3) == 0 &&
kernel_math_error(regs, "simd math error"))
return;
/*
* Save the info for the exception handler and clear the error.
*/
task = current;
save_init_fpu(task);
task->thread.trap_no = 19;
task->thread.error_code = 0;
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = __SI_FAULT;
info.si_addr = rip;
/*
* The SIMD FPU exceptions are handled a little differently, as there
* is only a single status/control register. Thus, to determine which
* unmasked exception was caught we must mask the exception mask bits
* at 0x1f80, and then use these to mask the exception bits at 0x3f.
*/
mxcsr = get_fpu_mxcsr(task);
switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
case 0x000:
default:
break;
case 0x001: /* Invalid Op */
info.si_code = FPE_FLTINV;
break;
case 0x002: /* Denormalize */
case 0x010: /* Underflow */
info.si_code = FPE_FLTUND;
break;
case 0x004: /* Zero Divide */
info.si_code = FPE_FLTDIV;
break;
case 0x008: /* Overflow */
info.si_code = FPE_FLTOVF;
break;
case 0x020: /* Precision */
info.si_code = FPE_FLTRES;
break;
}
force_sig_info(SIGFPE, &info, task);
}
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
{
}
#if 0
asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
{
}
#endif
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
*
* Careful.. There are problems with IBM-designed IRQ13 behaviour.
* Don't touch unless you *really* know how it works.
*/
asmlinkage void math_state_restore(void)
{
struct task_struct *me = current;
clts(); /* Allow maths ops (or we recurse) */
if (!used_math())
init_fpu(me);
restore_fpu_checking(&me->thread.i387.fxsave);
me->thread_info->status |= TS_USEDFPU;
}
void do_call_debug(struct pt_regs *regs)
{
notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT);
}
static trap_info_t trap_table[] = {
{ 0, 0, (__KERNEL_CS|0x3), 0, (unsigned long)divide_error },
{ 1, 0, (__KERNEL_CS|0x3), 0, (unsigned long)debug },
{ 3, 3, (__KERNEL_CS|0x3), 0, (unsigned long)int3 },
{ 4, 3, (__KERNEL_CS|0x3), 0, (unsigned long)overflow },
{ 5, 3, (__KERNEL_CS|0x3), 0, (unsigned long)bounds },
{ 6, 0, (__KERNEL_CS|0x3), 0, (unsigned long)invalid_op },
{ 7, 0, (__KERNEL_CS|0x3), 0, (unsigned long)device_not_available },
{ 9, 0, (__KERNEL_CS|0x3), 0, (unsigned long)coprocessor_segment_overrun},
{ 10, 0, (__KERNEL_CS|0x3), 0, (unsigned long)invalid_TSS },
{ 11, 0, (__KERNEL_CS|0x3), 0, (unsigned long)segment_not_present },
{ 12, 0, (__KERNEL_CS|0x3), 0, (unsigned long)stack_segment },
{ 13, 0, (__KERNEL_CS|0x3), 0, (unsigned long)general_protection },
{ 14, 0, (__KERNEL_CS|0x3), 0, (unsigned long)page_fault },
{ 15, 0, (__KERNEL_CS|0x3), 0, (unsigned long)spurious_interrupt_bug },
{ 16, 0, (__KERNEL_CS|0x3), 0, (unsigned long)coprocessor_error },
{ 17, 0, (__KERNEL_CS|0x3), 0, (unsigned long)alignment_check },
#ifdef CONFIG_X86_MCE
{ 18, 0, (__KERNEL_CS|0x3), 0, (unsigned long)machine_check },
#endif
{ 19, 0, (__KERNEL_CS|0x3), 0, (unsigned long)simd_coprocessor_error },
{ SYSCALL_VECTOR, 3, (__KERNEL_CS|0x3), 0, (unsigned long)system_call },
{ 0, 0, 0, 0, 0 }
};
void __init trap_init(void)
{
int ret;
ret = HYPERVISOR_set_trap_table(trap_table);
if (ret)
printk("HYPERVISOR_set_trap_table faild: error %d\n",
ret);
#ifdef CONFIG_IA32_EMULATION
set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
#endif
/*
* Should be a barrier for any external CPU state.
*/
cpu_init();
}
/* Actual parsing is done early in setup.c. */
static int __init oops_dummy(char *s)
{
panic_on_oops = 1;
return -1;
}
__setup("oops=", oops_dummy);
static int __init kstack_setup(char *s)
{
kstack_depth_to_print = simple_strtoul(s,NULL,0);
return 0;
}
__setup("kstack=", kstack_setup);
@@ -0,0 +1,190 @@
/*
* linux/arch/x86_64/kernel/vsyscall.c
*
* Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
* Copyright 2003 Andi Kleen, SuSE Labs.
*
* Thanks to hpa@transmeta.com for some useful hint.
* Special thanks to Ingo Molnar for his early experience with
* a different vsyscall implementation for Linux/IA32 and for the name.
*
* vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
* at virtual address -10Mbyte+1024bytes etc... There are at max 8192
* vsyscalls. One vsyscall can reserve more than 1 slot to avoid
* jumping out of line if necessary.
*
* Note: the concept clashes with user mode linux. If you use UML just
* set the kernel.vsyscall sysctl to 0.
*/
/*
* TODO 2001-03-20:
*
* 1) make page fault handler detect faults on page1-page-last of the vsyscall
* virtual space, and make it increase %rip and write -ENOSYS in %rax (so
* we'll be able to upgrade to a new glibc without upgrading kernel after
* we add more vsyscalls.
* 2) Possibly we need a fixmap table for the vsyscalls too if we want
* to avoid SIGSEGV and we want to return -EFAULT from the vsyscalls as well.
* Can we segfault inside a "syscall"? We can fix this anytime and those fixes
* won't be visible for userspace. Not fixing this is a noop for correct programs,
* broken programs will segfault and there's no security risk until we choose to
* fix it.
*
* These are not urgent things that we need to address only before shipping the first
* production binary kernels.
*/
#include <linux/time.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/seqlock.h>
#include <linux/jiffies.h>
#include <asm/vsyscall.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/fixmap.h>
#include <asm/errno.h>
#include <asm/io.h>
#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
#define force_inline __attribute__((always_inline)) inline
int __sysctl_vsyscall __section_sysctl_vsyscall = 1;
seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED;
#include <asm/unistd.h>
static force_inline void timeval_normalize(struct timeval * tv)
{
time_t __sec;
__sec = tv->tv_usec / 1000000;
if (__sec)
{
tv->tv_usec %= 1000000;
tv->tv_sec += __sec;
}
}
static force_inline void do_vgettimeofday(struct timeval * tv)
{
long sequence, t;
unsigned long sec, usec;
do {
sequence = read_seqbegin(&__xtime_lock);
sec = __xtime.tv_sec;
usec = (__xtime.tv_nsec / 1000) +
(__jiffies - __wall_jiffies) * (1000000 / HZ);
if (__vxtime.mode == VXTIME_TSC) {
sync_core();
rdtscll(t);
if (t < __vxtime.last_tsc) t = __vxtime.last_tsc;
usec += ((t - __vxtime.last_tsc) *
__vxtime.tsc_quot) >> 32;
/* See comment in x86_64 do_gettimeofday. */
} else {
usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) -
__vxtime.last) * __vxtime.quot) >> 32;
}
} while (read_seqretry(&__xtime_lock, sequence));
tv->tv_sec = sec + usec / 1000000;
tv->tv_usec = usec % 1000000;
}
/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */
static force_inline void do_get_tz(struct timezone * tz)
{
*tz = __sys_tz;
}
static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
{
int ret;
asm volatile("syscall"
: "=a" (ret)
: "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber );
return ret;
}
static force_inline long time_syscall(long *t)
{
long secs;
asm volatile("syscall"
: "=a" (secs)
: "0" (__NR_time),"D" (t) : __syscall_clobber);
return secs;
}
static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
{
if (unlikely(!__sysctl_vsyscall))
return gettimeofday(tv,tz);
if (tv)
do_vgettimeofday(tv);
if (tz)
do_get_tz(tz);
return 0;
}
/* This will break when the xtime seconds get inaccurate, but that is
* unlikely */
static time_t __vsyscall(1) vtime(time_t *t)
{
if (unlikely(!__sysctl_vsyscall))
return time_syscall(t);
else if (t)
*t = __xtime.tv_sec;
return __xtime.tv_sec;
}
static long __vsyscall(2) venosys_0(void)
{
return -ENOSYS;
}
static long __vsyscall(3) venosys_1(void)
{
return -ENOSYS;
}
static void __init map_vsyscall(void)
{
extern char __vsyscall_0;
unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
}
extern void __set_fixmap_user (enum fixed_addresses, unsigned long, pgprot_t);
static void __init map_vsyscall_user(void)
{
extern char __vsyscall_0;
unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
__set_fixmap_user(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
}
static int __init vsyscall_init(void)
{
BUG_ON(((unsigned long) &vgettimeofday !=
VSYSCALL_ADDR(__NR_vgettimeofday)));
BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
map_vsyscall();
map_vsyscall_user(); /* establish tranlation for user address space */
sysctl_vsyscall = 1;
return 0;
}
__initcall(vsyscall_init);
@@ -0,0 +1,223 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/user.h>
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/apm_bios.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/tty.h>
#include <linux/ioctl32.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/mmx.h>
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/nmi.h>
#include <asm/kdebug.h>
#include <asm/unistd.h>
#include <asm/tlbflush.h>
#include <asm/kdebug.h>
extern spinlock_t rtc_lock;
#ifdef CONFIG_SMP
extern void __write_lock_failed(rwlock_t *rw);
extern void __read_lock_failed(rwlock_t *rw);
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
extern struct drive_info_struct drive_info;
EXPORT_SYMBOL(drive_info);
#endif
extern unsigned long get_cmos_time(void);
/* platform dependent support */
EXPORT_SYMBOL(boot_cpu_data);
//EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
// EXPORT_SYMBOL(pm_power_off);
EXPORT_SYMBOL(get_cmos_time);
EXPORT_SYMBOL(__down_failed);
EXPORT_SYMBOL(__down_failed_interruptible);
EXPORT_SYMBOL(__down_failed_trylock);
EXPORT_SYMBOL(__up_wakeup);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy_nocheck);
EXPORT_SYMBOL(ip_compute_csum);
/* Delay loops */
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__delay);
EXPORT_SYMBOL(__const_udelay);
EXPORT_SYMBOL(__get_user_1);
EXPORT_SYMBOL(__get_user_2);
EXPORT_SYMBOL(__get_user_4);
EXPORT_SYMBOL(__get_user_8);
EXPORT_SYMBOL(__put_user_1);
EXPORT_SYMBOL(__put_user_2);
EXPORT_SYMBOL(__put_user_4);
EXPORT_SYMBOL(__put_user_8);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strncpy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(clear_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(copy_user_generic);
EXPORT_SYMBOL(copy_from_user);
EXPORT_SYMBOL(copy_to_user);
EXPORT_SYMBOL(copy_in_user);
EXPORT_SYMBOL(strnlen_user);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
#endif
#ifdef CONFIG_PCI
EXPORT_SYMBOL(pcibios_penalize_isa_irq);
EXPORT_SYMBOL(pci_mem_start);
#endif
EXPORT_SYMBOL(copy_page);
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(cpu_pda);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(cpu_data);
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(__write_lock_failed);
EXPORT_SYMBOL(__read_lock_failed);
EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
EXPORT_SYMBOL(cpu_callout_map);
#endif
#ifdef CONFIG_VT
EXPORT_SYMBOL(screen_info);
#endif
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(rtc_lock);
/* EXPORT_SYMBOL_GPL(set_nmi_callback);
EXPORT_SYMBOL_GPL(unset_nmi_callback); */
/* Export string functions. We normally rely on gcc builtin for most of these,
but gcc sometimes decides not to inline them. */
#undef memcpy
#undef memset
#undef memmove
#undef memchr
#undef strlen
#undef strcpy
#undef strncmp
#undef strncpy
#undef strchr
#undef strcmp
#undef strcpy
#undef strcat
#undef memcmp
extern void * memset(void *,int,__kernel_size_t);
extern size_t strlen(const char *);
extern void * memmove(void * dest,const void *src,size_t count);
extern char * strcpy(char * dest,const char *src);
extern int strcmp(const char * cs,const char * ct);
extern void *memchr(const void *s, int c, size_t n);
extern void * memcpy(void *,const void *,__kernel_size_t);
extern void * __memcpy(void *,const void *,__kernel_size_t);
extern char * strcat(char *, const char *);
extern int memcmp(const void * cs,const void * ct,size_t count);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(memcmp);
#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
/* prototypes are wrong, these are assembly with custom calling functions */
extern void rwsem_down_read_failed_thunk(void);
extern void rwsem_wake_thunk(void);
extern void rwsem_downgrade_thunk(void);
extern void rwsem_down_write_failed_thunk(void);
EXPORT_SYMBOL(rwsem_down_read_failed_thunk);
EXPORT_SYMBOL(rwsem_wake_thunk);
EXPORT_SYMBOL(rwsem_downgrade_thunk);
EXPORT_SYMBOL(rwsem_down_write_failed_thunk);
#endif
EXPORT_SYMBOL(empty_zero_page);
#ifdef CONFIG_HAVE_DEC_LOCK
EXPORT_SYMBOL(_atomic_dec_and_lock);
#endif
EXPORT_SYMBOL(die_chain);
EXPORT_SYMBOL(register_die_notifier);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(cpu_sibling_map);
EXPORT_SYMBOL(smp_num_siblings);
#endif
extern void do_softirq_thunk(void);
EXPORT_SYMBOL(do_softirq_thunk);
void out_of_line_bug(void);
EXPORT_SYMBOL(out_of_line_bug);
EXPORT_SYMBOL(init_level4_pgt);
extern unsigned long __supported_pte_mask;
EXPORT_SYMBOL(__supported_pte_mask);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL_GPL(flush_tlb_all);
#endif
EXPORT_SYMBOL(cpu_khz);
@@ -0,0 +1,26 @@
#
# Makefile for the linux x86_64-specific parts of the memory manager.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
CFLAGS += -Iarch/$(XENARCH)/mm
obj-y := init.o fault.o ioremap.o pageattr.o hypervisor.o
c-obj-y := extable.o
#obj-y := init.o fault.o ioremap.o extable.o pageattr.o
#c-obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
c-obj-$(CONFIG_DISCONTIGMEM) += numa.o
c-obj-$(CONFIG_K8_NUMA) += k8topology.o
hugetlbpage-y = ../../../i386/mm/hugetlbpage.o
c-link :=
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/x86_64/mm/$(notdir $@) $@
obj-y += $(c-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
@@ -0,0 +1,591 @@
/*
* linux/arch/x86-64/mm/fault.c
*
* Copyright (C) 1995 Linus Torvalds
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs.
*/
#include <linux/config.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/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/compiler.h>
#include <linux/module.h>
#include <linux/percpu.h>
#include <linux/kprobes.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/smp.h>
#include <asm/tlbflush.h>
#include <asm/proto.h>
#include <asm/kdebug.h>
#include <asm-generic/sections.h>
#include <asm/kdebug.h>
DEFINE_PER_CPU(pgd_t *, cur_pgd);
void bust_spinlocks(int yes)
{
int loglevel_save = console_loglevel;
if (yes) {
oops_in_progress = 1;
} else {
#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;
}
}
/* Sometimes the CPU reports invalid exceptions on prefetch.
Check that here and ignore.
Opcode checker based on code by Richard Brunner */
static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr,
unsigned long error_code)
{
unsigned char *instr = (unsigned char *)(regs->rip);
int scan_more = 1;
int prefetch = 0;
unsigned char *max_instr = instr + 15;
/* If it was a exec fault ignore */
if (error_code & (1<<4))
return 0;
/* Code segments in LDT could have a non zero base. Don't check
when that's possible */
if (regs->cs & (1<<2))
return 0;
if ((regs->cs & 3) != 0 && regs->rip >= TASK_SIZE)
return 0;
while (scan_more && instr < max_instr) {
unsigned char opcode;
unsigned char instr_hi;
unsigned char instr_lo;
if (__get_user(opcode, 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. In long mode, the CPU will signal
invalid opcode if some of these prefixes are
present so we will never get here anyway */
scan_more = ((instr_lo & 7) == 0x6);
break;
case 0x40:
/* In AMD64 long mode, 0x40 to 0x4F are valid REX prefixes
Need to figure out under what instruction mode the
instruction was issued ... */
/* Could check the LDT for lm, but for now it's good
enough to assume that long mode only uses well known
segments or kernel. */
scan_more = ((regs->cs & 3) == 0) || (regs->cs == __USER_CS);
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 in all modes. */
scan_more = !instr_lo || (instr_lo>>1) == 1;
break;
case 0x00:
/* Prefetch instruction is 0x0F0D or 0x0F18 */
scan_more = 0;
if (__get_user(opcode, instr))
break;
prefetch = (instr_lo == 0xF) &&
(opcode == 0x0D || opcode == 0x18);
break;
default:
scan_more = 0;
break;
}
}
return prefetch;
}
static int bad_address(void *p)
{
unsigned long dummy;
return __get_user(dummy, (unsigned long *)p);
}
void dump_pagetable(unsigned long address)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
pgd = (pgd_t *)per_cpu(cur_pgd, smp_processor_id());
pgd += pgd_index(address);
printk("PGD %lx ", pgd_val(*pgd));
if (bad_address(pgd)) goto bad;
if (!pgd_present(*pgd)) goto ret;
pud = __pud_offset_k((pud_t *)pgd_page(*pgd), address);
if (bad_address(pud)) goto bad;
printk("PUD %lx ", pud_val(*pud));
if (!pud_present(*pud)) goto ret;
pmd = pmd_offset(pud, address);
if (bad_address(pmd)) goto bad;
printk("PMD %lx ", pmd_val(*pmd));
if (!pmd_present(*pmd)) goto ret;
pte = pte_offset_kernel(pmd, address);
if (bad_address(pte)) goto bad;
printk("PTE %lx", pte_val(*pte));
ret:
printk("\n");
return;
bad:
printk("BAD\n");
}
static const char errata93_warning[] =
KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n"
KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n"
KERN_ERR "******* Please consider a BIOS update.\n"
KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n";
/* Workaround for K8 erratum #93 & buggy BIOS.
BIOS SMM functions are required to use a specific workaround
to avoid corruption of the 64bit RIP register on C stepping K8.
A lot of BIOS that didn't get tested properly miss this.
The OS sees this as a page fault with the upper 32bits of RIP cleared.
Try to work around it here.
Note we only handle faults in kernel here. */
static int is_errata93(struct pt_regs *regs, unsigned long address)
{
static int warned;
if (address != regs->rip)
return 0;
if ((address >> 32) != 0)
return 0;
address |= 0xffffffffUL << 32;
if ((address >= (u64)_stext && address <= (u64)_etext) ||
(address >= MODULES_VADDR && address <= MODULES_END)) {
if (!warned) {
printk(errata93_warning);
warned = 1;
}
regs->rip = address;
return 1;
}
return 0;
}
int unhandled_signal(struct task_struct *tsk, int sig)
{
if (tsk->pid == 1)
return 1;
/* Warn for strace, but not for gdb */
if (!test_ti_thread_flag(tsk->thread_info, TIF_SYSCALL_TRACE) &&
(tsk->ptrace & PT_PTRACED))
return 0;
return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
(tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
}
static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
unsigned long error_code)
{
oops_begin();
printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
current->comm, address);
dump_pagetable(address);
__die("Bad pagetable", regs, error_code);
oops_end();
do_exit(SIGKILL);
}
/*
* Handle a fault on the vmalloc or module mapping area
*/
static int vmalloc_fault(unsigned long address)
{
pgd_t *pgd, *pgd_ref;
pud_t *pud, *pud_ref;
pmd_t *pmd, *pmd_ref;
pte_t *pte, *pte_ref;
/* Copy kernel mappings over when needed. This can also
happen within a race in page table update. In the later
case just flush. */
pgd = pgd_offset(current->mm ?: &init_mm, address);
pgd_ref = pgd_offset_k(address);
if (pgd_none(*pgd_ref))
return -1;
if (pgd_none(*pgd))
set_pgd(pgd, *pgd_ref);
/* Below here mismatches are bugs because these lower tables
are shared */
pud = pud_offset(pgd, address);
pud_ref = pud_offset(pgd_ref, address);
if (pud_none(*pud_ref))
return -1;
if (pud_none(*pud) || pud_page(*pud) != pud_page(*pud_ref))
BUG();
pmd = pmd_offset(pud, address);
pmd_ref = pmd_offset(pud_ref, address);
if (pmd_none(*pmd_ref))
return -1;
if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
BUG();
pte_ref = pte_offset_kernel(pmd_ref, address);
if (!pte_present(*pte_ref))
return -1;
pte = pte_offset_kernel(pmd, address);
if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref))
BUG();
__flush_tlb_all();
return 0;
}
int page_fault_trace = 0;
int exception_trace = 1;
#define MEM_VERBOSE 1
#ifdef MEM_VERBOSE
#define MEM_LOG(_f, _a...) \
printk("fault.c:[%d]-> " _f "\n", \
__LINE__ , ## _a )
#else
#define MEM_LOG(_f, _a...) ((void)0)
#endif
/*
* 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 fault was an instruction fetch
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
const struct exception_table_entry *fixup;
int write;
siginfo_t info;
if (!user_mode(regs))
error_code &= ~4; /* means kernel */
#ifdef CONFIG_CHECKING
{
unsigned long gs;
struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
printk("page_fault: wrong gs %lx expected %p\n", gs, pda);
}
}
#endif
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
SIGSEGV) == NOTIFY_STOP)
return;
if (likely(regs->eflags & X86_EFLAGS_IF))
local_irq_enable();
if (unlikely(page_fault_trace))
printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code);
tsk = current;
mm = tsk->mm;
info.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 & 1) == 0.
*/
if (unlikely(address >= TASK_SIZE)) {
if (!(error_code & 5)) {
if (vmalloc_fault(address) < 0)
goto bad_area_nosemaphore;
return;
}
/*
* Don't take the mm semaphore here. If we fixup a prefetch
* fault we could otherwise deadlock.
*/
goto bad_area_nosemaphore;
}
if (unlikely(error_code & (1 << 3)))
pgtable_bad(address, regs, error_code);
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
if (unlikely(in_atomic() || !mm))
goto bad_area_nosemaphore;
again:
/* 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 occuring 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->rip))
goto bad_area_nosemaphore;
down_read(&mm->mmap_sem);
}
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (likely(vma->vm_start <= address))
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
if (error_code & 4) {
// XXX: align red zone size with ABI
if (address + 128 < regs->rsp)
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:
info.si_code = SEGV_ACCERR;
write = 0;
switch (error_code & 3) {
default: /* 3: write, present */
/* fall through */
case 2: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
write++;
break;
case 1: /* read, present */
goto bad_area;
case 0: /* read, not present */
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
/*
* 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 1:
tsk->min_flt++;
break;
case 2:
tsk->maj_flt++;
break;
case 0:
goto do_sigbus;
default:
goto out_of_memory;
}
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:
#ifdef CONFIG_IA32_EMULATION
/* 32bit vsyscall. map on demand. */
if (test_thread_flag(TIF_IA32) &&
address >= VSYSCALL32_BASE && address < VSYSCALL32_END) {
if (map_syscall32(mm, address) < 0)
goto out_of_memory2;
return;
}
#endif
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
if (is_prefetch(regs, address, error_code))
return;
/* Work around K8 erratum #100 K8 in compat mode
occasionally jumps to illegal addresses >4GB. We
catch this here in the page fault handler because
these addresses are not reachable. Just detect this
case and return. Any code segment in LDT is
compatibility mode. */
if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) &&
(address >> 32))
return;
if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
printk(
"%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, tsk->pid, address, regs->rip,
regs->rsp, error_code);
}
tsk->thread.cr2 = address;
/* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14;
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code has been set above */
info.si_addr = (void __user *)address;
force_sig_info(SIGSEGV, &info, tsk);
return;
}
no_context:
/* Are we prepared to handle this kernel fault? */
fixup = search_exception_tables(regs->rip);
if (fixup) {
regs->rip = fixup->fixup;
return;
}
/*
* Hall of shame of CPU/BIOS bugs.
*/
if (is_prefetch(regs, address, error_code))
return;
if (is_errata93(regs, address))
return;
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
oops_begin();
if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
else
printk(KERN_ALERT "Unable to handle kernel paging request");
printk(" at %016lx RIP: \n" KERN_ALERT,address);
printk_address(regs->rip);
printk("\n");
dump_pagetable(address);
__die("Oops", regs, error_code);
/* Executive summary in case the body of the oops scrolled away */
printk(KERN_EMERG "CR2: %016lx\n", address);
oops_end();
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 (current->pid == 1) {
yield();
goto again;
}
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;
tsk->thread.cr2 = address;
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *)address;
force_sig_info(SIGBUS, &info, tsk);
return;
}
@@ -0,0 +1,645 @@
/******************************************************************************
* mm/hypervisor.c
*
* Update page tables via the hypervisor.
*
* Copyright (c) 2002-2004, K A Fraser
*
* This file may be 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.
*/
/*
* Jun Nakajima <jun.nakajima@intel.com>
* Added hypercalls for x86-64.
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/multicall.h>
#include <asm-xen/balloon.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/percpu.h>
#endif
/*
* This suffices to protect us if we ever move to SMP domains.
* Further, it protects us against interrupts. At the very least, this is
* required for the network driver which flushes the update queue before
* pushing new receive buffers.
*/
static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
/* Linux 2.6 isn't using the traditional batched interface. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define QUEUE_SIZE 2048
#define pte_offset_kernel pte_offset
#else
#ifdef CONFIG_SMP
#define QUEUE_SIZE 1
#else
/* #define QUEUE_SIZE 128 */
#define QUEUE_SIZE 1
#endif
#endif
DEFINE_PER_CPU(mmu_update_t, update_queue[QUEUE_SIZE]);
DEFINE_PER_CPU(unsigned int, mmu_update_queue_idx);
/*
* MULTICALL_flush_page_update_queue:
* This is a version of the flush which queues as part of a multicall.
*/
void MULTICALL_flush_page_update_queue(void)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
unsigned int _idx;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
if ( (_idx = idx) != 0 )
{
per_cpu(mmu_update_queue_idx, cpu) = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
queue_multicall3(__HYPERVISOR_mmu_update,
(unsigned long)&per_cpu(update_queue[0], cpu),
(unsigned long)_idx,
(unsigned long)NULL);
}
spin_unlock_irqrestore(&update_lock, flags);
}
static inline void __flush_page_update_queue(void)
{
int cpu = smp_processor_id();
unsigned int _idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(mmu_update_queue_idx, cpu) = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
if ( unlikely(HYPERVISOR_mmu_update(&per_cpu(update_queue[0], cpu), _idx, NULL) < 0) )
{
printk(KERN_ALERT "Failed to execute MMU updates (returning to %lx)\n",
(unsigned long)__builtin_return_address(0));
BUG();
}
}
void _flush_page_update_queue(void)
{
int cpu = smp_processor_id();
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
if ( per_cpu(mmu_update_queue_idx, cpu) != 0 ) __flush_page_update_queue();
spin_unlock_irqrestore(&update_lock, flags);
}
static inline void increment_index(void)
{
int cpu = smp_processor_id();
per_cpu(mmu_update_queue_idx, cpu)++;
if ( unlikely(per_cpu(mmu_update_queue_idx, cpu) == QUEUE_SIZE) ) __flush_page_update_queue();
}
static inline void increment_index_and_flush(void)
{
int cpu = smp_processor_id();
per_cpu(mmu_update_queue_idx, cpu)++;
__flush_page_update_queue();
}
void queue_l1_entry_update(pte_t *ptr, unsigned long val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_l2_entry_update(pmd_t *ptr, pmd_t val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val.pmd;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pt_switch(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_NEW_BASEPTR;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_tlb_flush(void)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_TLB_FLUSH;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_invlpg(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).ptr |= ptr & PAGE_MASK;
per_cpu(update_queue[idx], cpu).val = MMUEXT_INVLPG;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L4_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pud_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L3_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pud_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pmd_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L2_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pmd_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L1_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_set_ldt(unsigned long ptr, unsigned long len)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND | ptr;
per_cpu(update_queue[idx], cpu).val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_machphys_update(unsigned long mfn, unsigned long pfn)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
per_cpu(update_queue[idx], cpu).val = pfn;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
/* queue and flush versions of the above */
void xen_l1_entry_update(pte_t *ptr, unsigned long val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_l2_entry_update(pmd_t *ptr, unsigned long val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_l3_entry_update(pud_t *ptr, unsigned long val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_l4_entry_update(pgd_t *ptr, unsigned long val)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pt_switch(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_NEW_BASEPTR;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_new_user_pt(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_NEW_USER_BASEPTR;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_tlb_flush(void)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_TLB_FLUSH;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_load_gs(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_LOAD_GS;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_invlpg(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).ptr |= ptr & PAGE_MASK;
per_cpu(update_queue[idx], cpu).val = MMUEXT_INVLPG;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pgd_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L4_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pgd_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pud_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L3_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pud_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pmd_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L2_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pmd_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pte_pin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L1_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pte_unpin(unsigned long ptr)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_set_ldt(unsigned long ptr, unsigned long len)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND | ptr;
per_cpu(update_queue[idx], cpu).val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_machphys_update(unsigned long mfn, unsigned long pfn)
{
int cpu = smp_processor_id();
int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
idx = per_cpu(mmu_update_queue_idx, cpu);
per_cpu(update_queue[idx], cpu).ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
per_cpu(update_queue[idx], cpu).val = pfn;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
unsigned long allocate_empty_lowmem_region(unsigned long pages)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
unsigned long *pfn_array;
unsigned long vstart;
unsigned long i;
unsigned int order = get_order(pages*PAGE_SIZE);
vstart = __get_free_pages(GFP_KERNEL, order);
if ( vstart == 0 )
return 0UL;
printk("vstart = %lx, order = %d\n", vstart, order);
scrub_pages(vstart, 1 << order);
pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
if ( pfn_array == NULL )
BUG();
for ( i = 0; i < (1<<order); i++ )
{
pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE)));
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
pfn_array[i] = pte->pte >> PAGE_SHIFT;
queue_l1_entry_update(pte, 0);
phys_to_machine_mapping[__pa(vstart)>>PAGE_SHIFT] = (u32)INVALID_P2M_ENTRY;
}
/* Flush updates through and flush the TLB. */
xen_tlb_flush();
balloon_put_pages(pfn_array, 1 << order);
vfree(pfn_array);
return vstart;
}
#endif /* CONFIG_XEN_PHYSDEV_ACCESS */
@@ -0,0 +1,941 @@
/*
* linux/arch/x86_64/mm/init.c
*
* Copyright (C) 1995 Linus Torvalds
* Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
* Copyright (C) 2002,2003 Andi Kleen <ak@suse.de>
*
* Jun Nakajima <jun.nakajima@intel.com>
* Modified for Xen.
*/
#include <linux/config.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/swap.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/proc_fs.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
#include <asm/fixmap.h>
#include <asm/e820.h>
#include <asm/apic.h>
#include <asm/tlb.h>
#include <asm/mmu_context.h>
#include <asm/proto.h>
#include <asm/smp.h>
#ifndef Dprintk
#define Dprintk(x...)
#endif
#ifdef CONFIG_GART_IOMMU
extern int swiotlb;
#endif
extern char _stext[];
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
extern unsigned long start_pfn;
static int init_mapping_done;
/*
* Use this until direct mapping is established, i.e. before __va() is
* avaialble in init_memory_mapping().
*/
#define addr_to_page(addr, page) \
(addr) &= PHYSICAL_PAGE_MASK; \
(page) = ((unsigned long *) ((unsigned long)(((mfn_to_pfn((addr) >> PAGE_SHIFT)) << PAGE_SHIFT) + __START_KERNEL_map)))
static void __make_page_readonly(unsigned long va)
{
unsigned long addr;
pte_t *pte;
unsigned long *page = (unsigned long *) init_level4_pgt;
addr = (unsigned long) page[pgd_index(va)];
addr_to_page(addr, page);
addr = page[pud_index(va)];
addr_to_page(addr, page);
addr = page[pmd_index(va)];
addr_to_page(addr, page);
pte = (pte_t *) &page[pte_index(va)];
xen_l1_entry_update(pte, (*(unsigned long*)pte) & ~_PAGE_RW);
__flush_tlb_one(addr);
}
static void __make_page_writable(unsigned long va)
{
unsigned long addr;
pte_t *pte;
unsigned long *page = (unsigned long *) init_level4_pgt;
addr = (unsigned long) page[pgd_index(va)];
addr_to_page(addr, page);
addr = page[pud_index(va)];
addr_to_page(addr, page);
addr = page[pmd_index(va)];
addr_to_page(addr, page);
pte = (pte_t *) &page[pte_index(va)];
xen_l1_entry_update(pte, (*(unsigned long*)pte)| _PAGE_RW);
__flush_tlb_one(addr);
}
/*
* Assume the tranlation is already established.
*/
void make_page_readonly(void *va)
{
pgd_t* pgd; pud_t *pud; pmd_t* pmd; pte_t *pte;
unsigned long addr = (unsigned long) va;
if (!init_mapping_done) {
__make_page_readonly(addr);
return;
}
pgd = pgd_offset_k(addr);
pud = pud_offset(pgd, addr);
pmd = pmd_offset(pud, addr);
pte = pte_offset_kernel(pmd, addr);
queue_l1_entry_update(pte, (*(unsigned long*)pte)&~_PAGE_RW);
__flush_tlb_one(addr);
}
void make_page_writable(void *va)
{
pgd_t* pgd; pud_t *pud; pmd_t* pmd; pte_t *pte;
unsigned long addr = (unsigned long) va;
if (!init_mapping_done) {
__make_page_writable(addr);
return;
}
pgd = pgd_offset_k(addr);
pud = pud_offset(pgd, addr);
pmd = pmd_offset(pud, addr);
pte = pte_offset_kernel(pmd, addr);
queue_l1_entry_update(pte, (*(unsigned long*)pte)|_PAGE_RW);
__flush_tlb_one(addr);
}
void make_pages_readonly(void* va, unsigned nr)
{
while ( nr-- != 0 ) {
make_page_readonly(va);
va = (void*)((unsigned long)va + PAGE_SIZE);
}
}
void make_pages_writable(void* va, unsigned nr)
{
while ( nr-- != 0 ) {
make_page_writable(va);
va = (void*)((unsigned long)va + PAGE_SIZE);
}
}
/*
* NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
* physical space so we can cache the place of the first one and move
* around without checking the pgd every time.
*/
void show_mem(void)
{
int i, total = 0, reserved = 0;
int shared = 0, cached = 0;
pg_data_t *pgdat;
struct page *page;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
for_each_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
page = pfn_to_page(pgdat->node_start_pfn + i);
total++;
if (PageReserved(page))
reserved++;
else if (PageSwapCache(page))
cached++;
else if (page_count(page))
shared += page_count(page) - 1;
}
}
printk("%d pages of RAM\n", total);
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
}
/* References to section boundaries */
extern char _text, _etext, _edata, __bss_start, _end[];
extern char __init_begin, __init_end;
int after_bootmem;
static void *spp_getpage(void)
{
void *ptr;
if (after_bootmem)
ptr = (void *) get_zeroed_page(GFP_ATOMIC);
else
ptr = alloc_bootmem_pages(PAGE_SIZE);
if (!ptr || ((unsigned long)ptr & ~PAGE_MASK))
panic("set_pte_phys: cannot allocate page data %s\n", after_bootmem?"after bootmem":"");
Dprintk("spp_getpage %p\n", ptr);
return ptr;
}
#define pgd_offset_u(address) (pgd_t *)(init_level4_user_pgt + pgd_index(address))
static inline pud_t *pud_offset_u(unsigned long address)
{
pud_t *pud = level3_user_pgt;
return pud + pud_index(address);
}
static void set_pte_phys(unsigned long vaddr,
unsigned long phys, pgprot_t prot, int user_mode)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte, new_pte;
Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys);
pgd = (user_mode ? pgd_offset_u(vaddr) : pgd_offset_k(vaddr));
if (pgd_none(*pgd)) {
printk("PGD FIXMAP MISSING, it should be setup in head.S!\n");
return;
}
pud = (user_mode ? pud_offset_u(vaddr) : pud_offset(pgd, vaddr));
if (pud_none(*pud)) {
pmd = (pmd_t *) spp_getpage();
make_page_readonly(pmd);
xen_pmd_pin(__pa(pmd));
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
if (pmd != pmd_offset(pud, 0)) {
printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0));
return;
}
}
pmd = pmd_offset(pud, vaddr);
if (pmd_none(*pmd)) {
pte = (pte_t *) spp_getpage();
make_page_readonly(pte);
xen_pte_pin(__pa(pte));
set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
if (pte != pte_offset_kernel(pmd, 0)) {
printk("PAGETABLE BUG #02!\n");
return;
}
}
new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
pte = pte_offset_kernel(pmd, vaddr);
if (!pte_none(*pte) &&
pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
pte_ERROR(*pte);
xen_l1_entry_update(pte, new_pte.pte);
/*
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
__flush_tlb_one(vaddr);
}
static void set_pte_phys_ma(unsigned long vaddr,
unsigned long phys, pgprot_t prot)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte, new_pte;
Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys);
pgd = pgd_offset_k(vaddr);
if (pgd_none(*pgd)) {
printk("PGD FIXMAP MISSING, it should be setup in head.S!\n");
return;
}
pud = pud_offset(pgd, vaddr);
if (pud_none(*pud)) {
pmd = (pmd_t *) spp_getpage();
make_page_readonly(pmd);
xen_pmd_pin(__pa(pmd));
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
if (pmd != pmd_offset(pud, 0)) {
printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0));
return;
}
}
pmd = pmd_offset(pud, vaddr);
if (pmd_none(*pmd)) {
pte = (pte_t *) spp_getpage();
make_page_readonly(pte);
xen_pte_pin(__pa(pte));
set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
if (pte != pte_offset_kernel(pmd, 0)) {
printk("PAGETABLE BUG #02!\n");
return;
}
}
new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
pte = pte_offset_kernel(pmd, vaddr);
if (!pte_none(*pte) &&
pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
pte_ERROR(*pte);
/*
* Note that the pte page is already RO, thus we want to use
* xen_l1_entry_update(), not set_pte().
*/
xen_l1_entry_update(pte,
(pfn_pte_ma(phys >> PAGE_SHIFT, prot).pte));
/*
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
__flush_tlb_one(vaddr);
}
#define SET_FIXMAP_KERNEL 0
#define SET_FIXMAP_USER 1
/* NOTE: this is meant to be run only at boot */
void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
printk("Invalid __set_fixmap\n");
return;
}
set_pte_phys(address, phys, prot, SET_FIXMAP_KERNEL);
}
/*
* At this point it only supports vsyscall area.
*/
void __set_fixmap_user (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
printk("Invalid __set_fixmap\n");
return;
}
set_pte_phys(address, phys, prot, SET_FIXMAP_USER);
#if 0
page = (unsigned long *) user_level3_pgt;
pud = page[pud_index(address)];
printk("pud = %p\n", pud);
pmd = (pmd_t *) spp_getpage();
printk("alloc pmd = %p\n", pmd);
make_page_readonly((unsigned long)pmd);
xen_pmd_pin(__pa(pmd));
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
printk("after set_pud\n");
pte = (pte_t *) spp_getpage();
printk("pte = %p\n");
make_page_readonly((unsigned long)pte);
xen_pte_pin(__pa(pte));
page = (unsigned long *) pud;
pud = page[pud_index(address)];
pmd = pmd_offset(pud, vaddr);
set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
#endif
}
void __set_fixmap_ma (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
printk("Invalid __set_fixmap\n");
return;
}
set_pte_phys_ma(address, phys, prot);
}
unsigned long __initdata table_start, table_end, tables_reserved;
#if 0
/*
* Get the machine PFN given va
*/
static unsigned long get_machine_pfn(unsigned long va)
{
unsigned long addr;
pte_t *pte;
unsigned long *page = (unsigned long *) init_level4_pgt;
addr = (unsigned long) page[pgd_index(va)];
addr &= PHYSICAL_PAGE_MASK;
page = (unsigned long *) ((unsigned long)(((mfn_to_pfn(addr >> PAGE_SHIFT)) << PAGE_SHIFT) + __START_KERNEL_map));
addr = page[pud_index(va)];
addr &= PHYSICAL_PAGE_MASK;
page = (unsigned long *) ((unsigned long)(((mfn_to_pfn(addr >> PAGE_SHIFT)) << PAGE_SHIFT) + __START_KERNEL_map));
addr = page[pmd_index(va)];
addr &= PHYSICAL_PAGE_MASK;
page = (unsigned long *) ((unsigned long)(((mfn_to_pfn(addr >> PAGE_SHIFT)) << PAGE_SHIFT)+ __START_KERNEL_map));
pte = (pte_t *) &page[pte_index(va)];
return (unsigned long) (pte->pte >> PAGE_SHIFT);
}
#endif
unsigned long get_machine_pfn(unsigned long addr)
{
pud_t* pud = pud_offset_k(addr);
pmd_t* pmd = pmd_offset(pud, addr);
pte_t *pte = pte_offset_kernel(pmd, addr);
return (pte->pte >> PAGE_SHIFT);
}
/*
* We start using from start_pfn
*/
static __init void *alloc_low_page(unsigned long *phys)
{
unsigned long pfn = table_end++;
*phys = (pfn << PAGE_SHIFT);
memset((void *) ((pfn << PAGE_SHIFT) + __START_KERNEL_map), 0, PAGE_SIZE);
return (void *)((pfn << PAGE_SHIFT) + __START_KERNEL_map);
}
#define PTE_SIZE PAGE_SIZE
static inline void __set_pte(pte_t *dst, pte_t val)
{
*dst = val;
}
void __init phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
{
long i, j, k;
unsigned long paddr;
i = pud_index(address);
pud = pud + i;
for (; i < PTRS_PER_PUD; pud++, i++) {
unsigned long pmd_phys;
pmd_t *pmd;
paddr = address + i*PUD_SIZE;
if (paddr >= end) {
for (; i < PTRS_PER_PUD; i++, pud++)
set_pud(pud, __pud(0));
break;
}
pmd = alloc_low_page(&pmd_phys);
make_page_readonly(pmd);
xen_pmd_pin(pmd_phys);
set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
unsigned long pte_phys;
pte_t *pte, *pte_save;
if (paddr >= end) {
for (; j < PTRS_PER_PMD; j++, pmd++)
set_pmd(pmd, __pmd(0));
break;
}
pte = alloc_low_page(&pte_phys);
pte_save = pte;
for (k = 0; k < PTRS_PER_PTE; pte++, k++, paddr += PTE_SIZE) {
if (paddr < (table_start << PAGE_SHIFT)
+ tables_reserved)
{
__set_pte(pte,
__pte(paddr | (_KERNPG_TABLE & ~_PAGE_RW)));
continue;
}
if (paddr >= end) {
for (; k < PTRS_PER_PTE; k++, pte++)
__set_pte(pte, __pte(0));
break;
}
__set_pte(pte, __pte(paddr | _KERNPG_TABLE));
}
pte = pte_save;
make_page_readonly(pte);
xen_pte_pin(pte_phys);
set_pmd(pmd, __pmd(pte_phys | _KERNPG_TABLE));
}
}
__flush_tlb();
}
static void __init find_early_table_space(unsigned long end)
{
unsigned long puds, pmds, ptes;
puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
ptes = (end + PTE_SIZE - 1) >> PAGE_SHIFT;
tables_reserved = round_up(puds*8, PAGE_SIZE) + round_up(pmds * 8, PAGE_SIZE)
+ round_up(ptes * 8, PAGE_SIZE);
table_start = start_pfn;
table_end = table_start;
}
/* Setup the direct mapping of the physical memory at PAGE_OFFSET.
This runs before bootmem is initialized and gets pages directly from the
physical memory. To access them they are temporarily mapped. */
void __init init_memory_mapping(unsigned long start, unsigned long end)
{
unsigned long next;
Dprintk("init_memory_mapping\n");
find_early_table_space(end);
start = (unsigned long)__va(start);
end = (unsigned long)__va(end);
for (; start < end; start = next) {
unsigned long pud_phys;
pud_t *pud = alloc_low_page(&pud_phys);
make_page_readonly(pud);
xen_pud_pin(pud_phys);
next = start + PGDIR_SIZE;
if (next > end)
next = end;
phys_pud_init(pud, __pa(start), __pa(next));
set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
}
early_printk("kernel direct mapping tables upto %lx @ %lx-%lx\n", end,
table_start<<PAGE_SHIFT,
table_end<<PAGE_SHIFT);
// start_pfn = table_end;
/*
* TBD: Need to calculate at runtime
*/
start_pfn = (8*0x100000) >> PAGE_SHIFT;
__flush_tlb_all();
init_mapping_done = 1;
}
extern struct x8664_pda cpu_pda[NR_CPUS];
void zap_low_mappings(void)
{
/* this is not required for Xen */
#if 0
swap_low_mappings();
#endif
}
#ifndef CONFIG_DISCONTIGMEM
void __init paging_init(void)
{
int i;
{
unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
/* unsigned int max_dma; */
/* max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; */
/* if (end_pfn < max_dma) */
zones_size[ZONE_DMA] = end_pfn;
#if 0
else {
zones_size[ZONE_DMA] = max_dma;
zones_size[ZONE_NORMAL] = end_pfn - max_dma;
}
#endif
free_area_init(zones_size);
}
__set_fixmap_ma(FIX_SHARED_INFO, xen_start_info.shared_info,
__pgprot(_KERNPG_TABLE));
HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
memset(empty_zero_page, 0, sizeof(empty_zero_page));
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
/* Setup mapping of lower 1st MB */
for (i = 0; i < NR_FIX_ISAMAPS; i++)
if (xen_start_info.flags & SIF_PRIVILEGED)
__set_fixmap_ma(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE,
__pgprot(_KERNPG_TABLE));
else
set_fixmap_ma_ro(FIX_ISAMAP_BEGIN - i,
virt_to_machine(empty_zero_page));
#endif
}
#endif
/* Unmap a kernel mapping if it exists. This is useful to avoid prefetches
from the CPU leading to inconsistent cache lines. address and size
must be aligned to 2MB boundaries.
Does nothing when the mapping doesn't exist. */
void __init clear_kernel_mapping(unsigned long address, unsigned long size)
{
unsigned long end = address + size;
BUG_ON(address & ~LARGE_PAGE_MASK);
BUG_ON(size & ~LARGE_PAGE_MASK);
for (; address < end; address += LARGE_PAGE_SIZE) {
pgd_t *pgd = pgd_offset_k(address);
pud_t *pud;
pmd_t *pmd;
if (pgd_none(*pgd))
continue;
pud = pud_offset(pgd, address);
if (pud_none(*pud))
continue;
pmd = pmd_offset(pud, address);
if (!pmd || pmd_none(*pmd))
continue;
if (0 == (pmd_val(*pmd) & _PAGE_PSE)) {
/* Could handle this, but it should not happen currently. */
printk(KERN_ERR
"clear_kernel_mapping: mapping has been split. will leak memory\n");
pmd_ERROR(*pmd);
}
set_pmd(pmd, __pmd(0));
}
__flush_tlb_all();
}
static inline int page_is_ram (unsigned long pagenr)
{
if (pagenr < start_pfn || pagenr >= end_pfn)
return 0;
return 1;
}
extern int swiotlb_force;
static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
kcore_vsyscall;
void __init mem_init(void)
{
int codesize, reservedpages, datasize, initsize;
int tmp;
#ifdef CONFIG_SWIOTLB
if (swiotlb_force)
swiotlb = 1;
if (!iommu_aperture &&
(end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu))
swiotlb = 1;
if (swiotlb)
swiotlb_init();
#endif
/* How many end-of-memory variables you have, grandma! */
max_low_pfn = end_pfn;
max_pfn = end_pfn;
num_physpages = end_pfn;
high_memory = (void *) __va(end_pfn * PAGE_SIZE);
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
reservedpages = 0;
/* this will put all low memory onto the freelists */
#ifdef CONFIG_DISCONTIGMEM
totalram_pages += numa_free_all_bootmem();
tmp = 0;
/* should count reserved pages here for all nodes */
#else
max_mapnr = end_pfn;
if (!mem_map) BUG();
totalram_pages += free_all_bootmem();
for (tmp = 0; tmp < end_pfn; tmp++)
/*
* Only count reserved RAM pages
*/
if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
reservedpages++;
#endif
after_bootmem = 1;
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
/* Register memory areas for /proc/kcore */
kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
VMALLOC_END-VMALLOC_START);
kclist_add(&kcore_kernel, &_stext, _end - _stext);
kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN);
kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START,
VSYSCALL_END - VSYSCALL_START);
printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
end_pfn << (PAGE_SHIFT-10),
codesize >> 10,
reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
initsize >> 10);
/*
* Subtle. SMP is doing its 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
}
extern char __initdata_begin[], __initdata_end[];
void free_initmem(void)
{
#ifdef __DO_LATER__
/*
* Some pages can be pinned, but some are not. Unpinning such pages
* triggers BUG().
*/
unsigned long addr;
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
set_page_count(virt_to_page(addr), 1);
memset((void *)(addr & ~(PAGE_SIZE-1)), 0xcc, PAGE_SIZE);
xen_pte_unpin(__pa(addr));
make_page_writable(__va(__pa(addr)));
/*
* Make pages from __PAGE_OFFSET address as well
*/
make_page_writable((void *)addr);
free_page(addr);
totalram_pages++;
}
memset(__initdata_begin, 0xba, __initdata_end - __initdata_begin);
printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10);
#endif
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < (unsigned long)&_end)
return;
printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
for (; start < end; start += PAGE_SIZE) {
ClearPageReserved(virt_to_page(start));
set_page_count(virt_to_page(start), 1);
free_page(start);
totalram_pages++;
}
}
#endif
void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
{
/* Should check here against the e820 map to avoid double free */
#ifdef CONFIG_DISCONTIGMEM
int nid = phys_to_nid(phys);
reserve_bootmem_node(NODE_DATA(nid), phys, len);
#else
reserve_bootmem(phys, len);
#endif
}
int kern_addr_valid(unsigned long addr)
{
unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (above != 0 && above != -1UL)
return 0;
pgd = pgd_offset_k(addr);
if (pgd_none(*pgd))
return 0;
pud = pud_offset_k(addr);
if (pud_none(*pud))
return 0;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
return 0;
if (pmd_large(*pmd))
return pfn_valid(pmd_pfn(*pmd));
pte = pte_offset_kernel(pmd, addr);
if (pte_none(*pte))
return 0;
return pfn_valid(pte_pfn(*pte));
}
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
extern int exception_trace, page_fault_trace;
static ctl_table debug_table2[] = {
{ 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL,
proc_dointvec },
#ifdef CONFIG_CHECKING
{ 100, "page-fault-trace", &page_fault_trace, sizeof(int), 0644, NULL,
proc_dointvec },
#endif
{ 0, }
};
static ctl_table debug_root_table2[] = {
{ .ctl_name = CTL_DEBUG, .procname = "debug", .mode = 0555,
.child = debug_table2 },
{ 0 },
};
static __init int x8664_sysctl_init(void)
{
register_sysctl_table(debug_root_table2, 1);
return 0;
}
__initcall(x8664_sysctl_init);
#endif
/* Pseudo VMAs to allow ptrace access for the vsyscall pages. x86-64 has two
different ones: one for 32bit and one for 64bit. Use the appropiate
for the target task. */
static struct vm_area_struct gate_vma = {
.vm_start = VSYSCALL_START,
.vm_end = VSYSCALL_END,
.vm_page_prot = PAGE_READONLY
};
static struct vm_area_struct gate32_vma = {
.vm_start = VSYSCALL32_BASE,
.vm_end = VSYSCALL32_END,
.vm_page_prot = PAGE_READONLY
};
struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
{
#ifdef CONFIG_IA32_EMULATION
if (test_tsk_thread_flag(tsk, TIF_IA32)) {
/* lookup code assumes the pages are present. set them up
now */
if (__map_syscall32(tsk->mm, VSYSCALL32_BASE) < 0)
return NULL;
return &gate32_vma;
}
#endif
return &gate_vma;
}
int in_gate_area(struct task_struct *task, unsigned long addr)
{
struct vm_area_struct *vma = get_gate_vma(task);
return (addr >= vma->vm_start) && (addr < vma->vm_end);
}
/* Use this when you have no reliable task/vma, typically from interrupt
* context. It is less reliable than using the task's vma and may give
* false positives.
*/
int in_gate_area_no_task(unsigned long addr)
{
return (((addr >= VSYSCALL_START) && (addr < VSYSCALL_END)) ||
((addr >= VSYSCALL32_BASE) && (addr < VSYSCALL32_END)));
}
@@ -0,0 +1,474 @@
/*
* arch/x86_64/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>
/*
* Reuse arch/xen/i396/mm/ioremap.c. Need to merge later
*/
#ifndef CONFIG_XEN_PHYSDEV_ACCESS
void * __ioremap(unsigned long phys_addr, unsigned long size,
unsigned long flags)
{
return NULL;
}
void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
{
return NULL;
}
void iounmap(volatile void __iomem *addr)
{
}
void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
{
return NULL;
}
void __init bt_iounmap(void *addr, unsigned long size)
{
}
#else
#if defined(__i386__)
/*
* 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 pte_pfn() in pgtable-2level.h to understand
* why this works.
*/
static inline int is_local_lowmem(unsigned long address)
{
extern unsigned long max_low_pfn;
unsigned long mfn = address >> PAGE_SHIFT;
unsigned long pfn = mfn_to_pfn(mfn);
return ((pfn < max_low_pfn) && (pfn_to_mfn(pfn) == mfn));
}
#elif defined(__x86_64__)
/*
*
*/
static inline int is_local_lowmem(unsigned long address)
{
return 0;
}
#endif
/*
* 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;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
/*
* Don't remap the low PCI/ISA area, it's always mapped..
*/
if (phys_addr >= 0x0 && last_addr < 0x100000)
return isa_bus_to_virt(phys_addr);
#endif
/*
* 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_LOCAL;
}
/*
* 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;
if (direct_remap_area_pages(&init_mm, (unsigned long) addr, phys_addr,
size, __pgprot(_PAGE_PRESENT | _PAGE_RW |
_PAGE_DIRTY | _PAGE_ACCESSED
#if defined(__x86_64__)
| _PAGE_USER
#endif
| flags), domid)) {
vunmap((void __force *) addr);
return NULL;
}
return (void __iomem *) (offset + (char __iomem *)addr);
}
/**
* 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;
}
void iounmap(volatile void __iomem *addr)
{
struct vm_struct *p;
if ((void __force *) addr <= high_memory)
return;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
if ((unsigned long) addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
return;
#endif
p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
if (!p) {
printk("__iounmap: bad address %p\n", addr);
return;
}
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();
}
kfree(p);
}
#if defined(__i386__)
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;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
/*
* Don't remap the low PCI/ISA area, it's always mapped..
*/
if (phys_addr >= 0x0 && last_addr < 0x100000)
return isa_bus_to_virt(phys_addr);
#endif
/*
* 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_ma(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;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
if (virt_addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
return;
#endif
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;
}
}
#endif /* defined(__i386__) */
#endif /* CONFIG_XEN_PHYSDEV_ACCESS */
/* These hacky macros avoid phys->machine translations. */
#define __direct_pte(x) ((pte_t) { (x) } )
#define __direct_mk_pte(page_nr,pgprot) \
__direct_pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
#define direct_mk_pte_phys(physpage, pgprot) \
__direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
static inline void direct_remap_area_pte(pte_t *pte,
unsigned long address,
unsigned long size,
mmu_update_t **v)
{
unsigned long end;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
if (address >= end)
BUG();
do {
(*v)->ptr = virt_to_machine(pte);
(*v)++;
address += PAGE_SIZE;
pte++;
} while (address && (address < end));
}
static inline int direct_remap_area_pmd(struct mm_struct *mm,
pmd_t *pmd,
unsigned long address,
unsigned long size,
mmu_update_t **v)
{
unsigned long end;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
if (address >= end)
BUG();
do {
pte_t *pte = (mm == &init_mm) ?
pte_alloc_kernel(mm, pmd, address) :
pte_alloc_map(mm, pmd, address);
if (!pte)
return -ENOMEM;
direct_remap_area_pte(pte, address, end - address, v);
pte_unmap(pte);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0;
}
int __direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long size,
mmu_update_t *v)
{
pgd_t * dir;
unsigned long end = address + size;
int error;
#if defined(__i386__)
dir = pgd_offset(mm, address);
#elif defined (__x86_64)
dir = (mm == &init_mm) ?
pgd_offset_k(address):
pgd_offset(mm, address);
#endif
if (address >= end)
BUG();
spin_lock(&mm->page_table_lock);
do {
pud_t *pud;
pmd_t *pmd;
error = -ENOMEM;
pud = pud_alloc(mm, dir, address);
if (!pud)
break;
pmd = pmd_alloc(mm, pud, address);
if (!pmd)
break;
error = 0;
direct_remap_area_pmd(mm, pmd, address, end - address, &v);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
spin_unlock(&mm->page_table_lock);
return error;
}
int direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long machine_addr,
unsigned long size,
pgprot_t prot,
domid_t domid)
{
int i;
unsigned long start_address;
#define MAX_DIRECTMAP_MMU_QUEUE 130
mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
v = w = &u[0];
if (domid != DOMID_LOCAL) {
u[0].ptr = MMU_EXTENDED_COMMAND;
u[0].val = MMUEXT_SET_FOREIGNDOM;
u[0].val |= (unsigned long)domid << 16;
v = w = &u[1];
}
start_address = address;
flush_cache_all();
for (i = 0; i < size; i += PAGE_SIZE) {
if ((v - u) == MAX_DIRECTMAP_MMU_QUEUE) {
/* Fill in the PTE pointers. */
__direct_remap_area_pages(mm,
start_address,
address-start_address,
w);
if (HYPERVISOR_mmu_update(u, v - u, NULL) < 0)
return -EFAULT;
v = w;
start_address = address;
}
/*
* Fill in the machine address: PTE ptr is done later by
* __direct_remap_area_pages().
*/
v->val = (machine_addr & PAGE_MASK) | pgprot_val(prot);
machine_addr += PAGE_SIZE;
address += PAGE_SIZE;
v++;
}
if (v != w) {
/* get the ptep's filled in */
__direct_remap_area_pages(mm,
start_address,
address-start_address,
w);
if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0))
return -EFAULT;
}
flush_tlb_all();
return 0;
}
EXPORT_SYMBOL(direct_remap_area_pages);
@@ -0,0 +1,248 @@
/*
* Copyright 2002 Andi Kleen, SuSE Labs.
* Thanks to Ben LaHaise for precious feedback.
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
#include <asm/pgalloc.h>
#include <asm/io.h>
void pte_free(struct page *pte)
{
pte_t *ptep;
ptep = pfn_to_kaddr(page_to_pfn(pte));
xen_pte_unpin(__pa(ptep));
make_page_writable(ptep);
flush_page_update_queue();
__free_page(pte);
}
static inline pte_t *lookup_address(unsigned long address)
{
pgd_t *pgd = pgd_offset_k(address);
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (pgd_none(*pgd))
return NULL;
pud = pud_offset(pgd, address);
if (!pud_present(*pud))
return NULL;
pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd))
return NULL;
if (pmd_large(*pmd))
return (pte_t *)pmd;
pte = pte_offset_kernel(pmd, address);
if (pte && !pte_present(*pte))
pte = NULL;
return pte;
}
static struct page *split_large_page(unsigned long address, pgprot_t prot,
pgprot_t ref_prot)
{
int i;
unsigned long addr;
struct page *base = alloc_pages(GFP_KERNEL, 0);
pte_t *pbase;
if (!base)
return NULL;
address = __pa(address);
addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
pbase[i] = pfn_pte(addr >> PAGE_SHIFT,
addr == address ? prot : ref_prot);
}
return base;
}
static void flush_kernel_map(void *address)
{
if (0 && address && cpu_has_clflush) {
/* is this worth it? */
int i;
for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
asm volatile("clflush (%0)" :: "r" (address + i));
} else
asm volatile("wbinvd":::"memory");
if (address)
__flush_tlb_one((unsigned long) address);
else
__flush_tlb_all();
}
static inline void flush_map(unsigned long address)
{
on_each_cpu(flush_kernel_map, (void *)address, 1, 1);
}
struct deferred_page {
struct deferred_page *next;
struct page *fpage;
unsigned long address;
};
static struct deferred_page *df_list; /* protected by init_mm.mmap_sem */
static inline void save_page(unsigned long address, struct page *fpage)
{
struct deferred_page *df;
df = kmalloc(sizeof(struct deferred_page), GFP_KERNEL);
if (!df) {
flush_map(address);
__free_page(fpage);
} else {
df->next = df_list;
df->fpage = fpage;
df->address = address;
df_list = df;
}
}
/*
* No more special protections in this 2/4MB area - revert to a
* large page again.
*/
static void revert_page(unsigned long address, pgprot_t ref_prot)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t large_pte;
pgd = pgd_offset_k(address);
BUG_ON(pgd_none(*pgd));
pud = pud_offset(pgd,address);
BUG_ON(pud_none(*pud));
pmd = pmd_offset(pud, address);
BUG_ON(pmd_val(*pmd) & _PAGE_PSE);
pgprot_val(ref_prot) |= _PAGE_PSE;
large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot);
set_pte((pte_t *)pmd, large_pte);
}
static int
__change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
pgprot_t ref_prot)
{
pte_t *kpte;
struct page *kpte_page;
unsigned kpte_flags;
kpte = lookup_address(address);
if (!kpte) return 0;
kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
kpte_flags = pte_val(*kpte);
if (pgprot_val(prot) != pgprot_val(ref_prot)) {
if ((kpte_flags & _PAGE_PSE) == 0) {
set_pte(kpte, pfn_pte(pfn, prot));
} else {
/*
* split_large_page will take the reference for this change_page_attr
* on the split page.
*/
struct page *split = split_large_page(address, prot, ref_prot);
if (!split)
return -ENOMEM;
set_pte(kpte,mk_pte(split, ref_prot));
kpte_page = split;
}
get_page(kpte_page);
} else if ((kpte_flags & _PAGE_PSE) == 0) {
set_pte(kpte, pfn_pte(pfn, ref_prot));
__put_page(kpte_page);
} else
BUG();
/* on x86-64 the direct mapping set at boot is not using 4k pages */
BUG_ON(PageReserved(kpte_page));
switch (page_count(kpte_page)) {
case 1:
save_page(address, kpte_page);
revert_page(address, ref_prot);
break;
case 0:
BUG(); /* memleak and failed 2M page regeneration */
}
return 0;
}
/*
* Change the page attributes of an page in the linear mapping.
*
* This should be used when a page is mapped with a different caching policy
* than write-back somewhere - some CPUs do not like it when mappings with
* different caching policies exist. This changes the page attributes of the
* in kernel linear mapping too.
*
* The caller needs to ensure that there are no conflicting mappings elsewhere.
* This function only deals with the kernel linear map.
*
* Caller must call global_flush_tlb() after this.
*/
int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot)
{
int err = 0;
int i;
down_write(&init_mm.mmap_sem);
for (i = 0; i < numpages; i++, address += PAGE_SIZE) {
unsigned long pfn = __pa(address) >> PAGE_SHIFT;
err = __change_page_attr(address, pfn, prot, PAGE_KERNEL);
if (err)
break;
/* Handle kernel mapping too which aliases part of the
* lowmem */
if (__pa(address) < KERNEL_TEXT_SIZE) {
unsigned long addr2;
pgprot_t prot2 = prot;
addr2 = __START_KERNEL_map + __pa(address);
pgprot_val(prot2) &= ~_PAGE_NX;
err = __change_page_attr(addr2, pfn, prot2, PAGE_KERNEL_EXEC);
}
}
up_write(&init_mm.mmap_sem);
return err;
}
/* Don't call this for MMIO areas that may not have a mem_map entry */
int change_page_attr(struct page *page, int numpages, pgprot_t prot)
{
unsigned long addr = (unsigned long)page_address(page);
return change_page_attr_addr(addr, numpages, prot);
}
void global_flush_tlb(void)
{
struct deferred_page *df, *next_df;
down_read(&init_mm.mmap_sem);
df = xchg(&df_list, NULL);
up_read(&init_mm.mmap_sem);
if (!df)
return;
flush_map((df && !df->next) ? df->address : 0);
for (; df; df = next_df) {
next_df = df->next;
if (df->fpage)
__free_page(df->fpage);
kfree(df);
}
}
EXPORT_SYMBOL(change_page_attr);
EXPORT_SYMBOL(global_flush_tlb);
@@ -0,0 +1,41 @@
#
# Makefile for X86_64 specific PCI routines
#
# Reuse the i386 PCI subsystem
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
CFLAGS += -Iarch/$(XENARCH)/pci
CFLAGS += -Iarch/i386/pci
c-obj-y := i386.o
c-obj-y += fixup.o
c-obj-$(CONFIG_ACPI_PCI) += acpi.o
c-obj-y += legacy.o common.o
c-xen-obj-$(CONFIG_PCI_DIRECT)+= direct.o
c-xen-obj-y += irq.o
# mmconfig has a 64bit special
c-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
c-obj-$(CONFIG_NUMA) += k8-bus.o
c-direct-y += ../../i386/pci/direct.o
c-acpi-y += ../../i386/pci/acpi.o
c-legacy-y += ../../i386/pci/legacy.o
c-irq-y += ../../i386/pci/irq.o
c-common-y += ../../i386/pci/common.o
c-fixup-y += ../../i386/pci/fixup.o
c-i386-y += ../../i386/pci/i386.o
c-link :=
$(patsubst %.o,$(obj)/%.c,$(c-xen-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/xen/i386/pci/$(notdir $@) $@
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/i386/pci/$(notdir $@) $@
obj-y += $(c-obj-y)
obj-y += $(c-xen-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
@@ -0,0 +1,22 @@
#
# Makefile for X86_64 specific PCI routines
#
# Reuse the i386 PCI subsystem
#
CFLAGS += -I arch/i386/pci
obj-y := i386.o
obj-$(CONFIG_PCI_DIRECT)+= direct.o
obj-y += fixup.o
obj-$(CONFIG_ACPI_PCI) += acpi.o
obj-y += legacy.o irq.o common.o
# mmconfig has a 64bit special
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
direct-y += ../../i386/pci/direct.o
acpi-y += ../../i386/pci/acpi.o
legacy-y += ../../i386/pci/legacy.o
irq-y += ../../i386/pci/irq.o
common-y += ../../i386/pci/common.o
fixup-y += ../../i386/pci/fixup.o
i386-y += ../../i386/pci/i386.o
@@ -0,0 +1,27 @@
#ifndef _ASM_ARCH_HOOKS_H
#define _ASM_ARCH_HOOKS_H
#include <linux/interrupt.h>
/*
* linux/include/asm/arch_hooks.h
*
* define the architecture specific hooks
*/
/* these aren't arch hooks, they are generic routines
* that can be used by the hooks */
extern void init_ISA_irqs(void);
extern void apic_intr_init(void);
extern void smp_intr_init(void);
extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/* these are the defined hooks */
extern void intr_init_hook(void);
extern void pre_intr_init_hook(void);
extern void pre_setup_arch_hook(void);
extern void trap_init_hook(void);
extern void time_init_hook(void);
extern void mca_nmi_hook(void);
#endif
@@ -0,0 +1,41 @@
#ifndef _X86_64_BOOTSETUP_H
#define _X86_64_BOOTSETUP_H 1
extern char x86_boot_params[2048];
/*
* This is set up by the setup-routine at boot-time
*/
#define PARAM ((unsigned char *)x86_boot_params)
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
#define ALT_MEM_K (*(unsigned int *) (PARAM+0x1e0))
#define E820_MAP_NR (*(char*) (PARAM+E820NR))
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define SAVED_VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
#define KERNEL_START (*(unsigned int *) (PARAM+0x214))
#define INITRD_START (__pa(xen_start_info.mod_start))
#define INITRD_SIZE (xen_start_info.mod_len)
#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
#define EDD_NR (*(unsigned char *) (PARAM+EDDNR))
#define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF))
#define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
#define COMMAND_LINE saved_command_line
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
#endif
@@ -0,0 +1,228 @@
/* Written 2000 by Andi Kleen */
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
#include <linux/threads.h>
#include <asm/ldt.h>
#ifndef __ASSEMBLY__
#include <linux/string.h>
#include <asm/segment.h>
#include <asm/mmu.h>
// 8 byte segment descriptor
struct desc_struct {
u16 limit0;
u16 base0;
unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
} __attribute__((packed));
struct n_desc_struct {
unsigned int a,b;
};
enum {
GATE_INTERRUPT = 0xE,
GATE_TRAP = 0xF,
GATE_CALL = 0xC,
};
// 16byte gate
struct gate_struct {
u16 offset_low;
u16 segment;
unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
u16 offset_middle;
u32 offset_high;
u32 zero1;
} __attribute__((packed));
#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF)
#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
#define PTR_HIGH(x) ((unsigned long)(x) >> 32)
enum {
DESC_TSS = 0x9,
DESC_LDT = 0x2,
};
// LDT or TSS descriptor in the GDT. 16 bytes.
struct ldttss_desc {
u16 limit0;
u16 base0;
unsigned base1 : 8, type : 5, dpl : 2, p : 1;
unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
u32 base3;
u32 zero1;
} __attribute__((packed));
struct desc_ptr {
unsigned short size;
unsigned long address;
} __attribute__((packed)) ;
extern struct desc_ptr idt_descr, cpu_gdt_descr[NR_CPUS];
extern struct desc_ptr cpu_gdt_table[NR_CPUS][GDT_ENTRIES];
#define get_cpu_gdt_table(_cpu) ((struct desc_ptr *)(cpu_gdt_descr[(_cpu)].address))
#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
#define clear_LDT() asm volatile("lldt %w0"::"r" (0))
/*
* This is the ldt that every process will get unless we need
* something other than this.
*/
extern struct desc_struct default_ldt[];
extern struct gate_struct idt_table[];
static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)
{
struct gate_struct s;
s.offset_low = PTR_LOW(func);
s.segment = __KERNEL_CS;
s.ist = ist;
s.p = 1;
s.dpl = dpl;
s.zero0 = 0;
s.zero1 = 0;
s.type = type;
s.offset_middle = PTR_MIDDLE(func);
s.offset_high = PTR_HIGH(func);
/* does not need to be atomic because it is only done once at setup time */
memcpy(adr, &s, 16);
}
static inline void set_intr_gate(int nr, void *func)
{
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0);
}
static inline void set_intr_gate_ist(int nr, void *func, unsigned ist)
{
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist);
}
static inline void set_system_gate(int nr, void *func)
{
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0);
}
static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type,
unsigned size)
{
struct ldttss_desc d;
memset(&d,0,sizeof(d));
d.limit0 = size & 0xFFFF;
d.base0 = PTR_LOW(tss);
d.base1 = PTR_MIDDLE(tss) & 0xFF;
d.type = type;
d.p = 1;
d.limit1 = (size >> 16) & 0xF;
d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF;
d.base3 = PTR_HIGH(tss);
memcpy(ptr, &d, 16);
}
static inline void set_tss_desc(unsigned cpu, void *addr)
{
set_tssldt_descriptor((struct ldttss_desc *)&get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS],
(unsigned long)addr,
DESC_TSS,
sizeof(struct tss_struct) - 1);
}
static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
{
set_tssldt_descriptor((struct ldttss_desc *)&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT],
(unsigned long)addr,
DESC_LDT, size * 8 - 1);
}
static inline void set_seg_base(unsigned cpu, int entry, void *base)
{
struct desc_struct *d = (struct desc_struct *)&get_cpu_gdt_table(cpu)[entry];
u32 addr = (u32)(u64)base;
BUG_ON((u64)base >> 32);
d->base0 = addr & 0xffff;
d->base1 = (addr >> 16) & 0xff;
d->base2 = (addr >> 24) & 0xff;
}
#define LDT_entry_a(info) \
((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
/* Don't allow setting of the lm bit. It is useless anyways because
64bit system calls require __USER_CS. */
#define LDT_entry_b(info) \
(((info)->base_addr & 0xff000000) | \
(((info)->base_addr & 0x00ff0000) >> 16) | \
((info)->limit & 0xf0000) | \
(((info)->read_exec_only ^ 1) << 9) | \
((info)->contents << 10) | \
(((info)->seg_not_present ^ 1) << 15) | \
((info)->seg_32bit << 22) | \
((info)->limit_in_pages << 23) | \
((info)->useable << 20) | \
/* ((info)->lm << 21) | */ \
0x7000)
#define LDT_empty(info) (\
(info)->base_addr == 0 && \
(info)->limit == 0 && \
(info)->contents == 0 && \
(info)->read_exec_only == 1 && \
(info)->seg_32bit == 0 && \
(info)->limit_in_pages == 0 && \
(info)->seg_not_present == 1 && \
(info)->useable == 0 && \
(info)->lm == 0)
#if TLS_SIZE != 24
# error update this code.
#endif
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
#if 0
u64 *gdt = (u64 *)(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN);
gdt[0] = t->tls_array[0];
gdt[1] = t->tls_array[1];
gdt[2] = t->tls_array[2];
#endif
#define C(i) \
HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), t->tls_array[i])
C(0); C(1); C(2);
#undef C
}
/*
* load one particular LDT into the current CPU
*/
extern inline void load_LDT_nolock (mm_context_t *pc, int cpu)
{
void *segments = pc->ldt;
int count = pc->size;
if (likely(!count))
segments = NULL;
queue_set_ldt((unsigned long)segments, count);
}
static inline void load_LDT(mm_context_t *pc)
{
int cpu = get_cpu();
load_LDT_nolock(pc, cpu);
put_cpu();
}
extern struct desc_ptr idt_descr;
#endif /* !__ASSEMBLY__ */
#endif
@@ -0,0 +1,136 @@
#ifndef _X8664_DMA_MAPPING_H
#define _X8664_DMA_MAPPING_H 1
/*
* IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
* documentation.
*/
#include <linux/config.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
#include <asm/swiotlb.h>
extern dma_addr_t bad_dma_address;
#define dma_mapping_error(x) \
(swiotlb ? swiotlb_dma_mapping_error(x) : ((x) == bad_dma_address))
void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
unsigned gfp);
void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle);
#ifdef CONFIG_GART_IOMMU
extern dma_addr_t dma_map_single(struct device *hwdev, void *ptr, size_t size,
int direction);
extern void dma_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
int direction);
#else
/* No IOMMU */
static inline dma_addr_t dma_map_single(struct device *hwdev, void *ptr,
size_t size, int direction)
{
dma_addr_t addr;
if (direction == DMA_NONE)
out_of_line_bug();
addr = virt_to_phys(ptr);
if ((addr+size) & ~*hwdev->dma_mask)
out_of_line_bug();
return phys_to_machine(addr);
}
static inline void dma_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
size_t size, int direction)
{
if (direction == DMA_NONE)
out_of_line_bug();
/* Nothing to do */
}
#endif
#define dma_map_page(dev,page,offset,size,dir) \
dma_map_single((dev), page_address(page)+(offset), (size), (dir))
static inline void dma_sync_single_for_cpu(struct device *hwdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
if (direction == DMA_NONE)
out_of_line_bug();
if (swiotlb)
return swiotlb_sync_single_for_cpu(hwdev,dma_handle,size,direction);
flush_write_buffers();
}
static inline void dma_sync_single_for_device(struct device *hwdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
if (direction == DMA_NONE)
out_of_line_bug();
if (swiotlb)
return swiotlb_sync_single_for_device(hwdev,dma_handle,size,direction);
flush_write_buffers();
}
static inline void dma_sync_sg_for_cpu(struct device *hwdev,
struct scatterlist *sg,
int nelems, int direction)
{
if (direction == DMA_NONE)
out_of_line_bug();
if (swiotlb)
return swiotlb_sync_sg_for_cpu(hwdev,sg,nelems,direction);
flush_write_buffers();
}
static inline void dma_sync_sg_for_device(struct device *hwdev,
struct scatterlist *sg,
int nelems, int direction)
{
if (direction == DMA_NONE)
out_of_line_bug();
if (swiotlb)
return swiotlb_sync_sg_for_device(hwdev,sg,nelems,direction);
flush_write_buffers();
}
extern int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
int nents, int direction);
extern void dma_unmap_sg(struct device *hwdev, struct scatterlist *sg,
int nents, int direction);
#define dma_unmap_page dma_unmap_single
extern int dma_supported(struct device *hwdev, u64 mask);
extern int dma_get_cache_alignment(void);
#define dma_is_consistent(h) 1
static inline int dma_set_mask(struct device *dev, u64 mask)
{
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
*dev->dma_mask = mask;
return 0;
}
static inline void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction dir)
{
flush_write_buffers();
}
#endif
@@ -0,0 +1,115 @@
/*
* fixmap.h: compile-time virtual memory allocation
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1998 Ingo Molnar
*/
#ifndef _ASM_FIXMAP_H
#define _ASM_FIXMAP_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/apicdef.h>
#include <asm/page.h>
#include <asm/vsyscall.h>
#include <asm/vsyscall32.h>
/*
* Here we define all the compile-time 'special' virtual
* addresses. The point is to have a constant address at
* compile time, but to set the physical address only
* in the boot process.
*
* these 'compile-time allocated' memory buffers are
* fixed-size 4k pages. (or larger if used with an increment
* highger than 1) use fixmap_set(idx,phys) to associate
* physical memory with fixmap indices.
*
* TLB entries of such buffers will not be flushed across
* task switches.
*/
enum fixed_addresses {
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
VSYSCALL_HPET,
FIX_HPET_BASE,
#ifdef CONFIG_X86_LOCAL_APIC
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
#endif
#ifdef CONFIG_X86_IO_APIC
FIX_IO_APIC_BASE_0,
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
#endif
FIX_SHARED_INFO,
FIX_GNTTAB,
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
#define NR_FIX_ISAMAPS 256
FIX_ISAMAP_END,
FIX_ISAMAP_BEGIN = FIX_ISAMAP_END + NR_FIX_ISAMAPS - 1,
#endif
__end_of_fixed_addresses
};
extern void __set_fixmap (enum fixed_addresses idx,
unsigned long phys, pgprot_t flags);
extern void __set_fixmap_ma (enum fixed_addresses idx,
unsigned long mach, pgprot_t flags);
#define set_fixmap(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL)
#define set_fixmap_ma(idx, phys) \
__set_fixmap_ma(idx, phys, PAGE_KERNEL)
#define set_fixmap_ma_ro(idx, phys) \
__set_fixmap_ma(idx, phys, PAGE_KERNEL_RO)
/*
* Some hardware wants to get fixmapped without caching.
*/
#define set_fixmap_nocache(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
#define clear_fixmap(idx) \
__set_fixmap(idx, 0, __pgprot(0))
#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE)
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */
#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL)
#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
extern void __this_fixmap_does_not_exist(void);
/*
* 'index to address' translation. If anyone tries to use the idx
* directly without translation, we catch the bug with a NULL-deference
* kernel oops. Illegal ranges of incoming indices are caught too.
*/
extern inline unsigned long fix_to_virt(const unsigned int idx)
{
/*
* this branch gets completely eliminated after inlining,
* except when someone tries to use fixaddr indices in an
* illegal way. (such as mixing up address types or using
* out-of-range indices).
*
* If it doesn't get removed, the linker will complain
* loudly with a reasonably clear error message..
*/
if (idx >= __end_of_fixed_addresses)
__this_fixmap_does_not_exist();
return __fix_to_virt(idx);
}
#endif
@@ -0,0 +1,204 @@
/*
* Architecture specific parts of the Floppy driver
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995
*
* Modifications for Xen are Copyright (c) 2004, Keir Fraser.
*/
#ifndef __ASM_XEN_X86_64_FLOPPY_H
#define __ASM_XEN_X86_64_FLOPPY_H
#include <linux/vmalloc.h>
/*
* The DMA channel used by the floppy controller cannot access data at
* addresses >= 16MB
*
* Went back to the 1MB limit, as some people had problems with the floppy
* driver otherwise. It doesn't matter much for performance anyway, as most
* floppy accesses go through the track buffer.
*/
#define _CROSS_64KB(a,s,vdma) \
(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
#include <linux/vmalloc.h>
/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */
#include <asm/dma.h>
#undef MAX_DMA_ADDRESS
#define MAX_DMA_ADDRESS 0
#define CROSS_64KB(a,s) (0)
#define fd_inb(port) inb_p(port)
#define fd_outb(value,port) outb_p(value,port)
#define fd_request_dma() (0)
#define fd_free_dma() ((void)0)
#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
#define fd_get_dma_residue() vdma_get_dma_residue(FLOPPY_DMA)
#define fd_dma_mem_alloc(size) vdma_mem_alloc(size)
#define fd_dma_mem_free(addr, size) vdma_mem_free(addr, size)
#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
static int virtual_dma_count;
static int virtual_dma_residue;
static char *virtual_dma_addr;
static int virtual_dma_mode;
static int doing_pdma;
static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
{
register unsigned char st;
#undef TRACE_FLPY_INT
#ifdef TRACE_FLPY_INT
static int calls=0;
static int bytes=0;
static int dma_wait=0;
#endif
if (!doing_pdma)
return floppy_interrupt(irq, dev_id, regs);
#ifdef TRACE_FLPY_INT
if(!calls)
bytes = virtual_dma_count;
#endif
{
register int lcount;
register char *lptr;
st = 1;
for(lcount=virtual_dma_count, lptr=virtual_dma_addr;
lcount; lcount--, lptr++) {
st=inb(virtual_dma_port+4) & 0xa0 ;
if(st != 0xa0)
break;
if(virtual_dma_mode)
outb_p(*lptr, virtual_dma_port+5);
else
*lptr = inb_p(virtual_dma_port+5);
}
virtual_dma_count = lcount;
virtual_dma_addr = lptr;
st = inb(virtual_dma_port+4);
}
#ifdef TRACE_FLPY_INT
calls++;
#endif
if(st == 0x20)
return IRQ_HANDLED;
if(!(st & 0x20)) {
virtual_dma_residue += virtual_dma_count;
virtual_dma_count=0;
#ifdef TRACE_FLPY_INT
printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
virtual_dma_count, virtual_dma_residue, calls, bytes,
dma_wait);
calls = 0;
dma_wait=0;
#endif
doing_pdma = 0;
floppy_interrupt(irq, dev_id, regs);
return IRQ_HANDLED;
}
#ifdef TRACE_FLPY_INT
if(!virtual_dma_count)
dma_wait++;
#endif
return IRQ_HANDLED;
}
static void fd_disable_dma(void)
{
doing_pdma = 0;
virtual_dma_residue += virtual_dma_count;
virtual_dma_count=0;
}
static int vdma_get_dma_residue(unsigned int dummy)
{
return virtual_dma_count + virtual_dma_residue;
}
static int fd_request_irq(void)
{
return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
"floppy", NULL);
}
static unsigned long vdma_mem_alloc(unsigned long size)
{
return (unsigned long) vmalloc(size);
}
static void vdma_mem_free(unsigned long addr, unsigned long size)
{
vfree((void *)addr);
}
static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
{
doing_pdma = 1;
virtual_dma_port = io;
virtual_dma_mode = (mode == DMA_MODE_WRITE);
virtual_dma_addr = addr;
virtual_dma_count = size;
virtual_dma_residue = 0;
return 0;
}
/* XEN: This trick to force 'virtual DMA' is from include/asm-m68k/floppy.h. */
#define FDC1 xen_floppy_init()
static int FDC2 = -1;
static int xen_floppy_init(void)
{
use_virtual_dma = 1;
can_use_virtual_dma = 1;
return 0x340;
}
/*
* Floppy types are stored in the rtc's CMOS RAM and so rtc_lock
* is needed to prevent corrupted CMOS RAM in case "insmod floppy"
* coincides with another rtc CMOS user. Paul G.
*/
#define FLOPPY0_TYPE ({ \
unsigned long flags; \
unsigned char val; \
spin_lock_irqsave(&rtc_lock, flags); \
val = (CMOS_READ(0x10) >> 4) & 15; \
spin_unlock_irqrestore(&rtc_lock, flags); \
val; \
})
#define FLOPPY1_TYPE ({ \
unsigned long flags; \
unsigned char val; \
spin_lock_irqsave(&rtc_lock, flags); \
val = CMOS_READ(0x10) & 15; \
spin_unlock_irqrestore(&rtc_lock, flags); \
val; \
})
#define N_FDC 2
#define N_DRIVE 8
#define FLOPPY_MOTOR_MASK 0xf0
#define EXTRA_FLOPPY_PARAMS
#endif /* __ASM_XEN_X86_64_FLOPPY_H */
@@ -0,0 +1,504 @@
/******************************************************************************
* hypercall.h
*
* Linux-specific hypervisor handling.
*
* Copyright (c) 2002-2004, K A Fraser
*
* This file may be 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.
*/
/*
* Benjamin Liu <benjamin.liu@intel.com>
* Jun Nakajima <jun.nakajima@intel.com>
* Ported to x86-64.
*
*/
#ifndef __HYPERCALL_H__
#define __HYPERCALL_H__
#include <asm-xen/xen-public/xen.h>
#define __syscall_clobber "r11","rcx","memory"
/*
* Assembler stubs for hyper-calls.
*/
static inline int
HYPERVISOR_set_trap_table(
trap_info_t *table)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_trap_table), "D" (table)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_mmu_update(
mmu_update_t *req, int count, int *success_count)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_mmu_update), "D" (req), "S" ((long)count),
"d" (success_count)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_set_gdt(
unsigned long *frame_list, int entries)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_gdt), "D" (frame_list), "S" ((long)entries)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_stack_switch(
unsigned long ss, unsigned long esp)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_stack_switch), "D" (ss), "S" (esp)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_set_callbacks(
unsigned long event_address, unsigned long failsafe_address,
unsigned long syscall_address)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_callbacks), "D" (event_address),
"S" (failsafe_address), "d" (syscall_address)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_fpu_taskswitch(
void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" ((unsigned long)__HYPERVISOR_fpu_taskswitch) : __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_yield(
void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_yield)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_block(
void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_block)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_shutdown(
void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_sched_op),
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift)))
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_reboot(
void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_sched_op),
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift)))
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_suspend(
unsigned long srec)
{
int ret;
/* NB. On suspend, control software expects a suspend record in %esi. */
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_sched_op),
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift))),
"S" (srec)
: __syscall_clobber );
return ret;
}
/*
* We can have the timeout value in a single argument for the hypercall, but
* that will break the common code.
*/
static inline long
HYPERVISOR_set_timer_op(
u64 timeout)
{
unsigned long timeout_hi = timeout >> 32;
unsigned long timeout_lo = timeout & 0xffffffff;
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_timer_op),
"D" (timeout_hi), "S" (timeout_lo)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_dom0_op(
dom0_op_t *dom0_op)
{
int ret;
dom0_op->interface_version = DOM0_INTERFACE_VERSION;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_dom0_op), "D" (dom0_op)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_set_debugreg(
int reg, unsigned long value)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_debugreg), "D" ((unsigned long)reg), "S" (value)
: __syscall_clobber );
return ret;
}
static inline unsigned long
HYPERVISOR_get_debugreg(
int reg)
{
unsigned long ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_get_debugreg), "D" ((unsigned long)reg)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_update_descriptor(
unsigned long ma, unsigned long word)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_update_descriptor), "D" (ma), "S" (word)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_set_fast_trap(
int idx)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_fast_trap), "D" ((unsigned long)idx)
: __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_dom_mem_op(
unsigned int op, unsigned long *extent_list,
unsigned long nr_extents, unsigned int extent_order)
{
int ret;
__asm__ __volatile__ (
"movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_dom_mem_op), "D" ((unsigned long)op), "S" (extent_list),
"d" (nr_extents), "g" ((unsigned long) extent_order), "g" ((unsigned long) DOMID_SELF)
: __syscall_clobber,"r8","r10");
return ret;
}
static inline int
HYPERVISOR_multicall(
void *call_list, int nr_calls)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_multicall), "D" (call_list), "S" ((unsigned long)nr_calls)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_update_va_mapping(
unsigned long page_nr, pte_t new_val, unsigned long flags)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_update_va_mapping),
"D" (page_nr), "S" (new_val.pte), "d" (flags)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_event_channel_op(
void *op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_event_channel_op), "D" (op)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_xen_version(
int cmd)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_xen_version), "D" ((unsigned long)cmd)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_console_io(
int cmd, int count, char *str)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_console_io), "D" ((unsigned long)cmd), "S" ((unsigned long)count), "d" (str)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_physdev_op(
void *physdev_op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_physdev_op), "D" (physdev_op)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_grant_table_op(
unsigned int cmd, void *uop, unsigned int count)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_grant_table_op), "D" ((unsigned long)cmd), "S" ((unsigned long)uop), "d" (count)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_update_va_mapping_otherdomain(
unsigned long page_nr, pte_t new_val, unsigned long flags, domid_t domid)
{
int ret;
__asm__ __volatile__ (
"movq %5, %%r10;" TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_update_va_mapping_otherdomain),
"D" (page_nr), "S" (new_val.pte), "d" (flags), "g" ((unsigned long)domid)
: __syscall_clobber,"r10");
return ret;
}
static inline int
HYPERVISOR_vm_assist(
unsigned int cmd, unsigned int type)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_vm_assist), "D" ((unsigned long)cmd), "S" ((unsigned long)type)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_switch_to_user(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" ((unsigned long)__HYPERVISOR_switch_to_user) : __syscall_clobber );
return ret;
}
static inline int
HYPERVISOR_boot_vcpu(
unsigned long vcpu, full_execution_context_t *ctxt)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" (__HYPERVISOR_boot_vcpu), "D" (vcpu), "S" (ctxt)
: __syscall_clobber);
return ret;
}
static inline int
HYPERVISOR_set_segment_base(
int reg, unsigned long value)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret)
: "0" ((unsigned long)__HYPERVISOR_set_segment_base), "D" ((unsigned long)reg), "S" (value)
: __syscall_clobber );
return ret;
}
#endif /* __HYPERCALL_H__ */
@@ -0,0 +1,365 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
#include <linux/config.h>
#include <asm/fixmap.h>
/*
* This file contains the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
* (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
* versions of the single-IO instructions (inb_p/inw_p/..).
*
* This file is not meant to be obfuscating: it's just complicated
* to (a) handle it all in a way that makes gcc able to optimize it
* as well as possible and (b) trying to avoid writing the same thing
* over and over again with slight variations and possibly making a
* mistake somewhere.
*/
/*
* Thanks to James van Artsdalen for a better timing-fix than
* the two short jumps: using outb's to a nonexistent port seems
* to guarantee better timings even on fast machines.
*
* On the other hand, I'd like to be sure of a non-existent port:
* I feel a bit unsafe about using 0x80 (should be safe, though)
*
* Linus
*/
/*
* Bit simplified and optimized by Jan Hubicka
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
*
* isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
* isa_read[wl] and isa_write[wl] fixed
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*/
#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
#else
#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
#endif
#ifdef REALLY_SLOW_IO
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
#else
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
/*
* Talk about misusing macros..
*/
#define __OUT1(s,x) \
extern inline void out##s(unsigned x value, unsigned short port) {
#define __OUT2(s,s1,s2) \
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
#define __OUT(s,s1,x) \
__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
#define __IN1(s) \
extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
#define __IN(s,s1,i...) \
__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
#define __INS(s) \
extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm__ __volatile__ ("rep ; ins" #s \
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define __OUTS(s) \
extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm__ __volatile__ ("rep ; outs" #s \
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define RETURN_TYPE unsigned char
__IN(b,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned short
__IN(w,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned int
__IN(l,"")
#undef RETURN_TYPE
__OUT(b,"b",char)
__OUT(w,"w",short)
__OUT(l,,int)
__INS(b)
__INS(w)
__INS(l)
__OUTS(b)
__OUTS(w)
__OUTS(l)
#define IO_SPACE_LIMIT 0xffff
#if defined(__KERNEL__) && __x86_64__
#include <linux/vmalloc.h>
#ifndef __i386__
/*
* Change virtual addresses to physical addresses and vv.
* These are pretty trivial
*/
extern inline unsigned long virt_to_phys(volatile void * address)
{
return __pa(address);
}
extern inline void * phys_to_virt(unsigned long address)
{
return __va(address);
}
#define virt_to_bus(_x) phys_to_machine(__pa(_x))
#define bus_to_virt(_x) __va(machine_to_phys(_x))
#endif
/*
* Change "struct page" to physical address.
*/
#ifdef CONFIG_DISCONTIGMEM
#include <asm/mmzone.h>
#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page)))
#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \
(unsigned long) bio_offset((bio)))
#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \
(unsigned long) (bv)->bv_offset)
#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
(((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \
((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
bvec_to_pseudophys((vec2))))
#else
// #define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page)))
#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \
(unsigned long) bio_offset((bio)))
#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \
(unsigned long) (bv)->bv_offset)
#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \
(((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \
((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
bvec_to_pseudophys((vec2))))
#endif
#include <asm-generic/iomap.h>
extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags);
extern inline void __iomem * ioremap (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, 0);
}
/*
* This one maps high address device memory and turns off caching for that area.
* it's useful if some control registers are in such an area and write combining
* or read caching is not desirable:
*/
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap(volatile void __iomem *addr);
/*
* ISA I/O bus memory addresses are 1:1 with the physical address.
*/
#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x
#define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x
#ifdef CONFIG_XEN_PHYSDEV_ACCESS
#define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x))
#else
#define isa_bus_to_virt(_x) isa_bus_to_virt_needs_PRIVILEGED_BUILD
#endif
/*
* However PCI ones are not necessarily 1:1 and therefore these interfaces
* are forbidden in portable PCI drivers.
*
* Allow them on x86 for legacy drivers, though.
*/
#define virt_to_bus(_x) phys_to_machine(__pa(_x))
#define bus_to_virt(_x) __va(machine_to_phys(_x))
/*
* readX/writeX() are used to access memory mapped devices. On some
* architectures the memory mapped IO stuff needs to be accessed
* differently. On the x86 architecture, we just read/write the
* memory location directly.
*/
static inline __u8 __readb(const volatile void __iomem *addr)
{
return *(__force volatile __u8 *)addr;
}
static inline __u16 __readw(const volatile void __iomem *addr)
{
return *(__force volatile __u16 *)addr;
}
static inline __u32 __readl(const volatile void __iomem *addr)
{
return *(__force volatile __u32 *)addr;
}
static inline __u64 __readq(const volatile void __iomem *addr)
{
return *(__force volatile __u64 *)addr;
}
#define readb(x) __readb(x)
#define readw(x) __readw(x)
#define readl(x) __readl(x)
#define readq(x) __readq(x)
#define readb_relaxed(a) readb(a)
#define readw_relaxed(a) readw(a)
#define readl_relaxed(a) readl(a)
#define readq_relaxed(a) readq(a)
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
#define __raw_readq readq
#define mmiowb()
#ifdef CONFIG_UNORDERED_IO
static inline void __writel(__u32 val, volatile void __iomem *addr)
{
volatile __u32 __iomem *target = addr;
asm volatile("movnti %1,%0"
: "=m" (*target)
: "r" (val) : "memory");
}
static inline void __writeq(__u64 val, volatile void __iomem *addr)
{
volatile __u64 __iomem *target = addr;
asm volatile("movnti %1,%0"
: "=m" (*target)
: "r" (val) : "memory");
}
#else
static inline void __writel(__u32 b, volatile void __iomem *addr)
{
*(__force volatile __u32 *)addr = b;
}
static inline void __writeq(__u64 b, volatile void __iomem *addr)
{
*(__force volatile __u64 *)addr = b;
}
#endif
static inline void __writeb(__u8 b, volatile void __iomem *addr)
{
*(__force volatile __u8 *)addr = b;
}
static inline void __writew(__u16 b, volatile void __iomem *addr)
{
*(__force volatile __u16 *)addr = b;
}
#define writeq(val,addr) __writeq((val),(addr))
#define writel(val,addr) __writel((val),(addr))
#define writew(val,addr) __writew((val),(addr))
#define writeb(val,addr) __writeb((val),(addr))
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
#define __raw_writeq writeq
void __memcpy_fromio(void*,unsigned long,unsigned);
void __memcpy_toio(unsigned long,const void*,unsigned);
static inline void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len)
{
__memcpy_fromio(to,(unsigned long)from,len);
}
static inline void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len)
{
__memcpy_toio((unsigned long)to,from,len);
}
void memset_io(volatile void __iomem *a, int b, size_t c);
/*
* ISA space is 'always mapped' on a typical x86 system, no need to
* explicitly ioremap() it. The fact that the ISA IO space is mapped
* to PAGE_OFFSET is pure coincidence - it does not mean ISA values
* are physical addresses. The following constant pointer can be
* used as the IO-area pointer (it can be iounmapped as well, so the
* analogy with PCI is quite large):
*/
#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
#define isa_readb(a) readb(__ISA_IO_base + (a))
#define isa_readw(a) readw(__ISA_IO_base + (a))
#define isa_readl(a) readl(__ISA_IO_base + (a))
#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a))
#define isa_writew(w,a) writew(w,__ISA_IO_base + (a))
#define isa_writel(l,a) writel(l,__ISA_IO_base + (a))
#define isa_memset_io(a,b,c) memset_io(__ISA_IO_base + (a),(b),(c))
#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c))
#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c))
/*
* Again, x86-64 does not require mem IO specific function.
*/
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d))
/**
* check_signature - find BIOS signatures
* @io_addr: mmio address to check
* @signature: signature block
* @length: length of signature
*
* Perform a signature comparison with the mmio address io_addr. This
* address should have been obtained by ioremap.
* Returns 1 on a match.
*/
static inline int check_signature(void __iomem *io_addr,
const unsigned char *signature, int length)
{
int retval = 0;
do {
if (readb(io_addr) != *signature)
goto out;
io_addr++;
signature++;
length--;
} while (length);
retval = 1;
out:
return retval;
}
/* Nothing to do */
#define dma_cache_inv(_start,_size) do { } while (0)
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
#define flush_write_buffers()
extern int iommu_bio_merge;
#define BIO_VMERGE_BOUNDARY iommu_bio_merge
#endif /* __KERNEL__ */
#endif
@@ -0,0 +1,36 @@
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
/*
* linux/include/asm/irq.h
*
* (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
*
* IRQ/IPI changes taken from work by Thomas Radke
* <tomsoft@informatik.tu-chemnitz.de>
*/
#include <linux/config.h>
#include <linux/sched.h>
/* include comes from machine specific directory */
#include "irq_vectors.h"
#include <asm/thread_info.h>
static __inline__ int irq_canonicalize(int irq)
{
return ((irq == 2) ? 9 : irq);
}
#ifdef CONFIG_X86_LOCAL_APIC
#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
#endif
#define KDB_VECTOR 0xf9
# define irq_ctx_init(cpu) do { } while (0)
struct irqaction;
struct pt_regs;
int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
#endif /* _ASM_IRQ_H */
@@ -0,0 +1,30 @@
/*
* arch/i386/mach-generic/io_ports.h
*
* Machine specific IO port address definition for generic.
* Written by Osamu Tomita <tomita@cinet.co.jp>
*/
#ifndef _MACH_IO_PORTS_H
#define _MACH_IO_PORTS_H
/* i8253A PIT registers */
#define PIT_MODE 0x43
#define PIT_CH0 0x40
#define PIT_CH2 0x42
/* i8259A PIC registers */
#define PIC_MASTER_CMD 0x20
#define PIC_MASTER_IMR 0x21
#define PIC_MASTER_ISR PIC_MASTER_CMD
#define PIC_MASTER_POLL PIC_MASTER_ISR
#define PIC_MASTER_OCW3 PIC_MASTER_ISR
#define PIC_SLAVE_CMD 0xa0
#define PIC_SLAVE_IMR 0xa1
/* i8259A PIC related value */
#define PIC_CASCADE_IR 2
#define MASTER_ICW4_DEFAULT 0x01
#define SLAVE_ICW4_DEFAULT 0x01
#define PIC_ICW4_AEOI 2
#endif /* !_MACH_IO_PORTS_H */
@@ -0,0 +1,137 @@
/*
* This file should contain #defines for all of the interrupt vector
* numbers used by this architecture.
*
* In addition, there are some standard defines:
*
* FIRST_EXTERNAL_VECTOR:
* The first free place for external interrupts
*
* SYSCALL_VECTOR:
* The IRQ vector a syscall makes the user to kernel transition
* under.
*
* TIMER_IRQ:
* The IRQ number the timer interrupt comes in at.
*
* NR_IRQS:
* The total number of interrupt vectors (including all the
* architecture specific interrupts) needed.
*
*/
#ifndef _ASM_IRQ_VECTORS_H
#define _ASM_IRQ_VECTORS_H
/*
* IDT vectors usable for external interrupt sources start
* at 0x20:
*/
#define FIRST_EXTERNAL_VECTOR 0x20
#define SYSCALL_VECTOR 0x80
/*
* Vectors 0x20-0x2f are used for ISA interrupts.
*/
#if 0
/*
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
*
* some of the following vectors are 'rare', they are merged
* into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
* TLB, reschedule and local APIC vectors are performance-critical.
*
* Vectors 0xf0-0xfa are free (reserved for future Linux use).
*/
#define SPURIOUS_APIC_VECTOR 0xff
#define ERROR_APIC_VECTOR 0xfe
#define INVALIDATE_TLB_VECTOR 0xfd
#define RESCHEDULE_VECTOR 0xfc
#define CALL_FUNCTION_VECTOR 0xfb
#define THERMAL_APIC_VECTOR 0xf0
/*
* Local APIC timer IRQ vector is on a different priority level,
* to work around the 'lost local interrupt if more than 2 IRQ
* sources per level' errata.
*/
#define LOCAL_TIMER_VECTOR 0xef
#endif
/*
* First APIC vector available to drivers: (vectors 0x30-0xee)
* we start at 0x31 to spread out vectors evenly between priority
* levels. (0x80 is the syscall vector)
*/
#define FIRST_DEVICE_VECTOR 0x31
#define FIRST_SYSTEM_VECTOR 0xef
/*
* 16 8259A IRQ's, 208 potential APIC interrupt sources.
* Right now the APIC is mostly only used for SMP.
* 256 vectors is an architectural limit. (we can have
* more than 256 devices theoretically, but they will
* have to use shared interrupts)
* Since vectors 0x00-0x1f are used/reserved for the CPU,
* the usable vector space is 0x20-0xff (224 vectors)
*/
#define NR_IPIS 8
#define RESCHEDULE_VECTOR 1
#define INVALIDATE_TLB_VECTOR 2
#define CALL_FUNCTION_VECTOR 3
/*
* The maximum number of vectors supported by i386 processors
* is limited to 256. For processors other than i386, NR_VECTORS
* should be changed accordingly.
*/
#define NR_VECTORS 256
#define FPU_IRQ 13
#define FIRST_VM86_IRQ 3
#define LAST_VM86_IRQ 15
#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
/*
* The flat IRQ space is divided into two regions:
* 1. A one-to-one mapping of real physical IRQs. This space is only used
* if we have physical device-access privilege. This region is at the
* start of the IRQ space so that existing device drivers do not need
* to be modified to translate physical IRQ numbers into our IRQ space.
* 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These
* are bound using the provided bind/unbind functions.
*/
#define PIRQ_BASE 0
#define NR_PIRQS 256
#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
#define NR_DYNIRQS 256
#define NR_IRQS (NR_PIRQS + NR_DYNIRQS)
#define NR_IRQ_VECTORS NR_IRQS
#define pirq_to_irq(_x) ((_x) + PIRQ_BASE)
#define irq_to_pirq(_x) ((_x) - PIRQ_BASE)
#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE)
#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE)
#ifndef __ASSEMBLY__
/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
extern int bind_virq_to_irq(int virq);
extern void unbind_virq_from_irq(int virq);
extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi);
extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
extern int bind_evtchn_to_irq(int evtchn);
extern void unbind_evtchn_from_irq(int evtchn);
extern void irq_suspend(void);
extern void irq_resume(void);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_IRQ_VECTORS_H */
@@ -0,0 +1,122 @@
/*
* include/asm-i386/mach-default/mach_time.h
*
* Machine specific set RTC function for generic.
* Split out from time.c by Osamu Tomita <tomita@cinet.co.jp>
*/
#ifndef _MACH_TIME_H
#define _MACH_TIME_H
#include <linux/mc146818rtc.h>
/* for check timing call set_rtc_mmss() 500ms */
/* used in arch/i386/time.c::do_timer_interrupt() */
#define USEC_AFTER 500000
#define USEC_BEFORE 500000
/*
* In order to set the CMOS clock precisely, set_rtc_mmss has to be
* called 500 ms after the second nowtime has started, because when
* nowtime is written into the registers of the CMOS clock, it will
* jump to the next second precisely 500 ms later. Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details.
*
* BUG: This routine does not handle hour overflow properly; it just
* sets the minutes. Usually you'll only notice that after reboot!
*/
static inline int mach_set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
unsigned char save_control, save_freq_select;
save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
cmos_minutes = CMOS_READ(RTC_MINUTES);
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(cmos_minutes);
/*
* since we're only adjusting minutes and seconds,
* don't interfere with hour overflow. This avoids
* messing with unknown time zones but requires your
* RTC not to be off by more than 15 minutes
*/
real_seconds = nowtime % 60;
real_minutes = nowtime / 60;
if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
real_minutes += 30; /* correct for half hour time zone */
real_minutes %= 60;
if (abs(real_minutes - cmos_minutes) < 30) {
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
}
CMOS_WRITE(real_seconds,RTC_SECONDS);
CMOS_WRITE(real_minutes,RTC_MINUTES);
} else {
printk(KERN_WARNING
"set_rtc_mmss: can't update from %d to %d\n",
cmos_minutes, real_minutes);
retval = -1;
}
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
* battery and quartz) will not reset the oscillator and will not
* update precisely 500 ms later. You won't find this mentioned in
* the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn
*/
CMOS_WRITE(save_control, RTC_CONTROL);
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
return retval;
}
static inline unsigned long mach_get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
int i;
/* The Linux interpretation of the CMOS clock register contents:
* When the Update-In-Progress (UIP) flag goes from 1 to 0, the
* RTC registers show the second which has precisely just started.
* Let's hope other operating systems interpret the RTC the same way.
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
} while (sec != CMOS_READ(RTC_SECONDS));
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
BCD_TO_BIN(day);
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
}
if ((year += 1900) < 1970)
year += 100;
return mktime(year, mon, day, hour, min, sec);
}
#endif /* !_MACH_TIME_H */
@@ -0,0 +1,48 @@
/*
* include/asm-i386/mach-default/mach_timer.h
*
* Machine specific calibrate_tsc() for generic.
* Split out from timer_tsc.c by Osamu Tomita <tomita@cinet.co.jp>
*/
/* ------ Calibrate the TSC -------
* Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
* Too much 64-bit arithmetic here to do this cleanly in C, and for
* accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
* output busy loop as low as possible. We avoid reading the CTC registers
* directly because of the awkward 8-bit access mechanism of the 82C54
* device.
*/
#ifndef _MACH_TIMER_H
#define _MACH_TIMER_H
#define CALIBRATE_LATCH (5 * LATCH)
static inline void mach_prepare_counter(void)
{
/* Set the Gate high, disable speaker */
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
/*
* Now let's take care of CTC channel 2
*
* Set the Gate high, program CTC channel 2 for mode 0,
* (interrupt on terminal count mode), binary count,
* load 5 * LATCH count, (LSB and MSB) to begin countdown.
*
* Some devices need a delay here.
*/
outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
}
static inline void mach_countup(unsigned long *count_p)
{
unsigned long count = 0;
do {
count++;
} while ((inb_p(0x61) & 0x20) == 0);
*count_p = count;
}
#endif /* !_MACH_TIMER_H */
@@ -0,0 +1,47 @@
/**
* 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.
**/
static char * __init machine_specific_memory_setup(void)
{
char *who;
unsigned long start_pfn, max_pfn;
who = "Xen";
start_pfn = 0;
max_pfn = xen_start_info.nr_pages;
e820.nr_map = 0;
add_memory_region(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn) - PFN_PHYS(start_pfn), E820_RAM);
return who;
}
void __init machine_specific_modify_cpu_capabilities(struct cpuinfo_x86 *c)
{
clear_bit(X86_FEATURE_VME, c->x86_capability);
clear_bit(X86_FEATURE_DE, c->x86_capability);
clear_bit(X86_FEATURE_PSE, c->x86_capability);
clear_bit(X86_FEATURE_PGE, c->x86_capability);
clear_bit(X86_FEATURE_SEP, c->x86_capability);
if (!(xen_start_info.flags & SIF_PRIVILEGED))
clear_bit(X86_FEATURE_MTRR, c->x86_capability);
}
extern void hypervisor_callback(void);
extern void failsafe_callback(void);
static void __init machine_specific_arch_setup(void)
{
HYPERVISOR_set_callbacks(
(unsigned long) hypervisor_callback,
(unsigned long) failsafe_callback,
(unsigned long) system_call);
machine_specific_modify_cpu_capabilities(&boot_cpu_data);
}
@@ -0,0 +1,5 @@
/* Hook to call BIOS initialisation function */
#define ARCH_SETUP machine_specific_arch_setup();
static void __init machine_specific_arch_setup(void);
@@ -0,0 +1,59 @@
/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
* which needs to alter them. */
static inline void smpboot_clear_io_apic_irqs(void)
{
#if 1
printk("smpboot_clear_io_apic_irqs\n");
#else
io_apic_irqs = 0;
#endif
}
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
{
#if 1
printk("smpboot_setup_warm_reset_vector\n");
#else
CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
Dprintk("1.\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
Dprintk("2.\n");
*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
Dprintk("3.\n");
#endif
}
static inline void smpboot_restore_warm_reset_vector(void)
{
/*
* Install writable page 0 entry to set BIOS data area.
*/
local_flush_tlb();
/*
* Paranoid: Set warm reset code and vector here back
* to default values.
*/
CMOS_WRITE(0, 0xf);
*((volatile long *) phys_to_virt(0x467)) = 0;
}
static inline void smpboot_setup_io_apic(void)
{
#if 1
printk("smpboot_setup_io_apic\n");
#else
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
*/
if (!skip_ioapic_setup && nr_ioapics)
setup_IO_APIC();
#endif
}
#define smp_found_config (HYPERVISOR_shared_info->n_vcpu > 1)
@@ -0,0 +1,77 @@
#ifndef __X86_64_MMU_CONTEXT_H
#define __X86_64_MMU_CONTEXT_H
#include <linux/config.h>
#include <asm/desc.h>
#include <asm/atomic.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
#include <asm/pda.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
/*
* possibly do the LDT unload here?
*/
int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void destroy_context(struct mm_struct *mm);
#ifdef CONFIG_SMP
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
if (read_pda(mmu_state) == TLBSTATE_OK)
write_pda(mmu_state, TLBSTATE_LAZY);
}
#else
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
}
#endif
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
unsigned cpu = smp_processor_id();
if (likely(prev != next)) {
/* stop flush ipis for the previous mm */
clear_bit(cpu, &prev->cpu_vm_mask);
#ifdef CONFIG_SMP
write_pda(mmu_state, TLBSTATE_OK);
write_pda(active_mm, next);
#endif
set_bit(cpu, &next->cpu_vm_mask);
load_cr3(next->pgd);
xen_new_user_pt(__pa(__user_pgd(next->pgd)));
if (unlikely(next->context.ldt != prev->context.ldt))
load_LDT_nolock(&next->context, cpu);
}
#ifdef CONFIG_SMP
else {
write_pda(mmu_state, TLBSTATE_OK);
if (read_pda(active_mm) != next)
out_of_line_bug();
if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
/* We were in lazy tlb mode and leave_mm disabled
* tlb flush IPI delivery. We must reload CR3
* to make sure to use no freed page tables.
*/
load_cr3(next->pgd);
xen_new_user_pt(__pa(__user_pgd(next->pgd)));
load_LDT_nolock(&next->context, cpu);
}
}
#endif
}
#define deactivate_mm(tsk,mm) do { \
load_gs_index(0); \
asm volatile("movl %0,%%fs"::"r"(0)); \
} while(0)
#define activate_mm(prev, next) do { \
switch_mm((prev),(next),NULL); \
flush_page_update_queue(); \
} while (0)
#endif
@@ -0,0 +1,228 @@
#ifndef _X86_64_PAGE_H
#define _X86_64_PAGE_H
#include <linux/config.h>
/* #include <linux/string.h> */
#ifndef __ASSEMBLY__
#include <linux/types.h>
#endif
#include <asm-xen/xen-public/xen.h>
#include <asm-xen/foreign_page.h>
#define arch_free_page(_page,_order) \
({ int foreign = PageForeign(_page); \
if (foreign) \
(PageForeignDestructor(_page))(_page); \
foreign; \
})
#define HAVE_ARCH_FREE_PAGE
#ifdef CONFIG_XEN_SCRUB_PAGES
#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
#else
#define scrub_pages(_p,_n) ((void)0)
#endif
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#ifdef __ASSEMBLY__
#define PAGE_SIZE (0x1 << PAGE_SHIFT)
#else
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & (__PHYSICAL_MASK << PAGE_SHIFT))
#define THREAD_ORDER 1
#ifdef __ASSEMBLY__
#define THREAD_SIZE (1 << (PAGE_SHIFT + THREAD_ORDER))
#else
#define THREAD_SIZE (1UL << (PAGE_SHIFT + THREAD_ORDER))
#endif
#define CURRENT_MASK (~(THREAD_SIZE-1))
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
void clear_page(void *);
void copy_page(void *, void *);
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
extern u32 *phys_to_machine_mapping;
#define pfn_to_mfn(_pfn) ((unsigned long) phys_to_machine_mapping[(unsigned int)(_pfn)])
#define mfn_to_pfn(_mfn) ((unsigned long) machine_to_phys_mapping[(unsigned int)(_mfn)])
static inline unsigned long phys_to_machine(unsigned long phys)
{
unsigned long machine = pfn_to_mfn(phys >> PAGE_SHIFT);
machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
return machine;
}
static inline unsigned long machine_to_phys(unsigned long machine)
{
unsigned long phys = mfn_to_pfn(machine >> PAGE_SHIFT);
phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
return phys;
}
/*
* These are used to make use of C type-checking..
*/
typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
typedef struct { unsigned long pgd; } pgd_t;
#define PTE_MASK PHYSICAL_PAGE_MASK
typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) (((x).pte & 1) ? machine_to_phys((x).pte) : \
(x).pte)
static inline unsigned long pmd_val(pmd_t x)
{
unsigned long ret = x.pmd;
if (ret) ret = machine_to_phys(ret);
return ret;
}
static inline unsigned long pud_val(pud_t x)
{
unsigned long ret = x.pud;
if (ret) ret = machine_to_phys(ret);
return ret;
}
static inline unsigned long pgd_val(pgd_t x)
{
unsigned long ret = x.pgd;
if (ret) ret = machine_to_phys(ret);
return ret;
}
#define pgprot_val(x) ((x).pgprot)
#define __pte_ma(x) ((pte_t) { (x) } )
static inline pte_t __pte(unsigned long x)
{
if (x & 1) x = phys_to_machine(x);
return ((pte_t) { (x) });
}
static inline pmd_t __pmd(unsigned long x)
{
if ((x & 1)) x = phys_to_machine(x);
return ((pmd_t) { (x) });
}
static inline pud_t __pud(unsigned long x)
{
if ((x & 1)) x = phys_to_machine(x);
return ((pud_t) { (x) });
}
static inline pgd_t __pgd(unsigned long x)
{
if ((x & 1)) x = phys_to_machine(x);
return ((pgd_t) { (x) });
}
#define __pgprot(x) ((pgprot_t) { (x) } )
extern unsigned long vm_stack_flags, vm_stack_flags32;
extern unsigned long vm_data_default_flags, vm_data_default_flags32;
extern unsigned long vm_force_exec32;
#define __START_KERNEL 0xffffffff80100000UL
#define __START_KERNEL_map 0xffffffff80000000UL
#define __PAGE_OFFSET 0xffff880000000000UL
#else
#define __START_KERNEL 0xffffffff80100000
#define __START_KERNEL_map 0xffffffff80000000
#define __PAGE_OFFSET 0xffff880000000000
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* See Documentation/x86_64/mm.txt for a description of the memory map. */
#define __PHYSICAL_MASK_SHIFT 46
#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)
#define __VIRTUAL_MASK_SHIFT 48
#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
#define KERNEL_TEXT_SIZE (40UL*1024*1024)
#define KERNEL_TEXT_START 0xffffffff80000000UL
#ifndef __ASSEMBLY__
#include <asm/bug.h>
/* Pure 2^n version of get_order */
extern __inline__ int get_order(unsigned long size)
{
int order;
size = (size-1) >> (PAGE_SHIFT-1);
order = -1;
do {
size >>= 1;
order++;
} while (size);
return order;
}
#endif /* __ASSEMBLY__ */
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol.
Otherwise you risk miscompilation. */
#define __pa(x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
/* __pa_symbol should be used for C visible symbols.
This seems to be the official gcc blessed way to do such arithmetic. */
#define __pa_symbol(x) \
({unsigned long v; \
asm("" : "=r" (v) : "0" (x)); \
__pa(v); })
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#ifndef CONFIG_DISCONTIGMEM
#define pfn_to_page(pfn) (mem_map + (pfn))
#define page_to_pfn(page) ((unsigned long)((page) - mem_map))
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#endif
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
#define VM_DATA_DEFAULT_FLAGS \
(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
#define __HAVE_ARCH_GATE_AREA 1
#endif /* __KERNEL__ */
#endif /* _X86_64_PAGE_H */
@@ -0,0 +1,22 @@
#ifndef _ASMx86_64_PARAM_H
#define _ASMx86_64_PARAM_H
#ifdef __KERNEL__
# define HZ 100 /* Internal kernel timer frequency */
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif
#ifndef HZ
#define HZ 100
#endif
#define EXEC_PAGESIZE 4096
#ifndef NOGROUP
#define NOGROUP (-1)
#endif
#define MAXHOSTNAMELEN 64 /* max length of hostname */
#endif
@@ -0,0 +1,148 @@
#ifndef __x8664_PCI_H
#define __x8664_PCI_H
#include <linux/config.h>
#include <asm/io.h>
#ifdef __KERNEL__
#include <linux/mm.h> /* for struct page */
/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
#ifdef CONFIG_PCI
extern unsigned int pcibios_assign_all_busses(void);
#else
#define pcibios_assign_all_busses() 0
#endif
#define pcibios_scan_all_fns(a, b) 0
extern int no_iommu, force_iommu;
extern unsigned long pci_mem_start;
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM (pci_mem_start)
#define PCIBIOS_MIN_CARDBUS_IO 0x4000
void pcibios_config_init(void);
struct pci_bus * pcibios_scan_root(int bus);
extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
void pcibios_set_master(struct pci_dev *dev);
void pcibios_penalize_isa_irq(int irq);
struct irq_routing_table *pcibios_get_irq_routing_table(void);
int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/scatterlist.h>
#include <linux/string.h>
#include <asm/page.h>
extern int iommu_setup(char *opt);
#ifdef CONFIG_GART_IOMMU
/* The PCI address space does equal the physical memory
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions
*
* On AMD64 it mostly equals, but we set it to zero to tell some subsystems
* that an IOMMU is available.
*/
#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0)
/*
* x86-64 always supports DAC, but sometimes it is useful to force
* devices through the IOMMU to get automatic sg list merging.
* Optional right now.
*/
extern int iommu_sac_force;
#define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force)
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
__u32 LEN_NAME;
#define pci_unmap_addr(PTR, ADDR_NAME) \
((PTR)->ADDR_NAME)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
(((PTR)->ADDR_NAME) = (VAL))
#define pci_unmap_len(PTR, LEN_NAME) \
((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
#else
/* No IOMMU */
#define PCI_DMA_BUS_IS_PHYS 1
#define pci_dac_dma_supported(pci_dev, mask) 1
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) (0)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif
#include <asm-generic/pci-dma-compat.h>
static inline dma64_addr_t
pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
{
return ((dma64_addr_t) page_to_phys(page) +
(dma64_addr_t) offset);
}
static inline struct page *
pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
{
return virt_to_page(__va(dma_addr));
}
static inline unsigned long
pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
{
return (dma_addr & ~PAGE_MASK);
}
static inline void
pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
{
}
static inline void
pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
{
flush_write_buffers();
}
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
static inline void pcibios_add_platform_entries(struct pci_dev *dev)
{
}
#endif /* __KERNEL__ */
/* generic pci stuff */
#ifdef CONFIG_PCI
#include <asm-generic/pci.h>
#endif
/* On Xen we have to scan all functions since Xen hides bridges from
* us. If a bridge is at fn=0 and that slot has a multifunction
* device, we won't find the additional devices without scanning all
* functions. */
#undef pcibios_scan_all_fns
#define pcibios_scan_all_fns(a, b) 1
#endif /* __x8664_PCI_H */
@@ -0,0 +1,85 @@
#ifndef X86_64_PDA_H
#define X86_64_PDA_H
#ifndef __ASSEMBLY__
#include <linux/stddef.h>
#include <linux/types.h>
#include <linux/cache.h>
/* Per processor datastructure. %gs points to it while the kernel runs */
struct x8664_pda {
struct task_struct *pcurrent; /* Current process */
unsigned long data_offset; /* Per cpu data offset from linker address */
struct x8664_pda *me; /* Pointer to itself */
unsigned long kernelstack; /* top of kernel stack for current */
unsigned long oldrsp; /* user rsp for system call */
unsigned long irqrsp; /* Old rsp for interrupts. */
int irqcount; /* Irq nesting counter. Starts with -1 */
int cpunumber; /* Logical CPU number */
char *irqstackptr; /* top of irqstack */
unsigned int __softirq_pending;
unsigned int __nmi_count; /* number of NMI on this CPUs */
unsigned long idle_timestamp;
struct mm_struct *active_mm;
int mmu_state;
unsigned apic_timer_irqs;
int kernel_mode; /* kernel or user mode */
} ____cacheline_aligned;
#define IRQSTACK_ORDER 2
#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER)
extern struct x8664_pda cpu_pda[];
/*
* There is no fast way to get the base address of the PDA, all the accesses
* have to mention %fs/%gs. So it needs to be done this Torvaldian way.
*/
#define sizeof_field(type,field) (sizeof(((type *)0)->field))
#define typeof_field(type,field) typeof(((type *)0)->field)
extern void __bad_pda_field(void);
#define pda_offset(field) offsetof(struct x8664_pda, field)
#define pda_to_op(op,field,val) do { \
switch (sizeof_field(struct x8664_pda, field)) { \
case 2: \
asm volatile(op "w %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
case 4: \
asm volatile(op "l %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
case 8: \
asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
default: __bad_pda_field(); \
} \
} while (0)
/*
* AK: PDA read accesses should be neither volatile nor have an memory clobber.
* Unfortunately removing them causes all hell to break lose currently.
*/
#define pda_from_op(op,field) ({ \
typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
switch (sizeof_field(struct x8664_pda, field)) { \
case 2: \
asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
case 4: \
asm volatile(op "l %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
case 8: \
asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
default: __bad_pda_field(); \
} \
ret__; })
#define read_pda(field) pda_from_op("mov",field)
#define write_pda(field,val) pda_to_op("mov",field,val)
#define add_pda(field,val) pda_to_op("add",field,val)
#define sub_pda(field,val) pda_to_op("sub",field,val)
#endif
#define PDA_STACKOFFSET (5*8)
#endif
@@ -0,0 +1,185 @@
#ifndef _X86_64_PGALLOC_H
#define _X86_64_PGALLOC_H
#include <asm/processor.h>
#include <asm/fixmap.h>
#include <asm/pda.h>
#include <linux/threads.h>
#include <linux/mm.h>
#include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */
void make_page_readonly(void *va);
void make_page_writable(void *va);
void make_pages_readonly(void *va, unsigned int nr);
void make_pages_writable(void *va, unsigned int nr);
#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD)
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
{
set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
flush_page_update_queue();
}
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
{
set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
flush_page_update_queue();
}
static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
{
set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
flush_page_update_queue();
}
/*
* We need to use the batch mode here, but pgd_pupulate() won't be
* be called frequently.
*/
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
set_pgd(__user_pgd(pgd), __pgd(_PAGE_TABLE | __pa(pud)));
flush_page_update_queue();
}
extern __inline__ pmd_t *get_pmd(void)
{
pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL);
if (!pmd)
return NULL;
make_page_readonly(pmd);
xen_pmd_pin(__pa(pmd));
flush_page_update_queue();
return pmd;
}
extern __inline__ void pmd_free(pmd_t *pmd)
{
BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
xen_pmd_unpin(__pa(pmd));
make_page_writable(pmd);
flush_page_update_queue();
free_page((unsigned long)pmd);
}
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
pmd_t *pmd = (pmd_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
if (!pmd)
return NULL;
make_page_readonly(pmd);
xen_pmd_pin(__pa(pmd));
flush_page_update_queue();
return pmd;
}
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
pud_t *pud = (pud_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
if (!pud)
return NULL;
make_page_readonly(pud);
xen_pud_pin(__pa(pud));
flush_page_update_queue();
return pud;
}
static inline void pud_free(pud_t *pud)
{
BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
xen_pud_unpin(__pa(pud));
make_page_writable(pud);
flush_page_update_queue();
free_page((unsigned long)pud);
}
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
/*
* We allocate two contiguous pages for kernel and user.
*/
unsigned boundary;
pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 1);
if (!pgd)
return NULL;
/*
* Copy kernel pointers in from init.
* Could keep a freelist or slab cache of those because the kernel
* part never changes.
*/
boundary = pgd_index(__PAGE_OFFSET);
memset(pgd, 0, boundary * sizeof(pgd_t));
memcpy(pgd + boundary,
init_level4_pgt + boundary,
(PTRS_PER_PGD - boundary) * sizeof(pgd_t));
memset(__user_pgd(pgd), 0, PAGE_SIZE); /* clean up user pgd */
make_pages_readonly(pgd, 2);
xen_pgd_pin(__pa(pgd)); /* kernel */
xen_pgd_pin(__pa(__user_pgd(pgd))); /* user */
/*
* Set level3_user_pgt for vsyscall area
*/
set_pgd(__user_pgd(pgd) + pgd_index(VSYSCALL_START),
mk_kernel_pgd(__pa_symbol(level3_user_pgt)));
flush_page_update_queue();
return pgd;
}
static inline void pgd_free(pgd_t *pgd)
{
BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
xen_pgd_unpin(__pa(pgd));
xen_pgd_unpin(__pa(__user_pgd(pgd)));
make_pages_writable(pgd, 2);
flush_page_update_queue();
free_pages((unsigned long)pgd, 1);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
if (!pte)
return NULL;
make_page_readonly(pte);
xen_pte_pin(__pa(pte));
flush_page_update_queue();
return pte;
}
static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
pte_t *pte = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
if (!pte)
return NULL;
make_page_readonly(pte);
xen_pte_pin(__pa(pte));
flush_page_update_queue();
return virt_to_page((unsigned long)pte);
}
/* Should really implement gc for free page table pages. This could be
done with a reference count in struct page. */
extern __inline__ void pte_free_kernel(pte_t *pte)
{
BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
xen_pte_unpin(__pa(pte));
make_page_writable(pte);
flush_page_update_queue();
free_page((unsigned long)pte);
}
extern void pte_free(struct page *pte);
//#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
#define __pte_free_tlb(tlb,x) pte_free((x))
#define __pmd_free_tlb(tlb,x) pmd_free((x))
#define __pud_free_tlb(tlb,x) pud_free((x))
#endif /* _X86_64_PGALLOC_H */
@@ -0,0 +1,527 @@
#ifndef _X86_64_PGTABLE_H
#define _X86_64_PGTABLE_H
/*
* This file contains the functions and defines necessary to modify and use
* the x86-64 page table tree.
*
* x86-64 has a 4 level table setup. Generic linux MM only supports
* three levels. The fourth level is currently a single static page that
* is shared by everybody and just contains a pointer to the current
* three level page setup on the beginning and some kernel mappings at
* the end. For more details see Documentation/x86_64/mm.txt
*/
#include <asm/processor.h>
#include <asm/fixmap.h>
#include <asm/bitops.h>
#include <linux/threads.h>
#include <asm/pda.h>
#include <asm-xen/hypervisor.h>
extern pud_t level3_user_pgt[512];
extern pud_t init_level4_pgt[];
extern pud_t init_level4_user_pgt[];
extern unsigned long __supported_pte_mask;
#define swapper_pg_dir NULL
extern int nonx_setup(char *str);
extern void paging_init(void);
extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
extern unsigned long pgkern_mask;
#define arbitrary_virt_to_machine(__va) ({0;})
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
#define PGDIR_SHIFT 39
#define PTRS_PER_PGD 512
/*
* PUDIR_SHIFT determines what a top-level page table entry can map
*/
#define PUD_SHIFT 30
#define PTRS_PER_PUD 512
/*
* PMD_SHIFT determines the size of the area a middle-level
* page table can map
*/
#define PMD_SHIFT 21
#define PTRS_PER_PMD 512
/*
* entries per page directory level
*/
#define PTRS_PER_PTE 512
#define pte_ERROR(e) \
printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
#define pmd_ERROR(e) \
printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
#define pud_ERROR(e) \
printk("%s:%d: bad pud %p(%016lx).\n", __FILE__, __LINE__, &(e), pud_val(e))
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
#define pgd_none(x) (!pgd_val(x))
#define pud_none(x) (!pud_val(x))
#define set_pte_batched(pteptr, pteval) \
queue_l1_entry_update(pteptr, (pteval))
extern inline int pud_present(pud_t pud) { return !pud_none(pud); }
#ifdef CONFIG_SMP
#define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte)
#else
#define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval.pte))
#if 0
static inline void set_pte(pte_t *dst, pte_t val)
{
*dst = val;
}
#endif
#endif
#define set_pmd(pmdptr, pmdval) xen_l2_entry_update(pmdptr, (pmdval).pmd)
#define set_pud(pudptr, pudval) xen_l3_entry_update(pudptr, (pudval).pud)
#define set_pgd(pgdptr, pgdval) xen_l4_entry_update(pgdptr, (pgdval).pgd)
extern inline void pud_clear (pud_t * pud)
{
set_pud(pud, __pud(0));
}
#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD)
extern inline void pgd_clear (pgd_t * pgd)
{
set_pgd(pgd, __pgd(0));
set_pgd(__user_pgd(pgd), __pgd(0));
}
#define pud_page(pud) \
((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
/*
* A note on implementation of this atomic 'get-and-clear' operation.
* This is actually very simple because Xen Linux can only run on a single
* processor. Therefore, we cannot race other processors setting the 'accessed'
* or 'dirty' bits on a page-table entry.
* Even if pages are shared between domains, that is not a problem because
* each domain will have separate page tables, with their own versions of
* accessed & dirty state.
*/
static inline pte_t ptep_get_and_clear(pte_t *xp)
{
pte_t pte = *xp;
if (pte.pte)
set_pte(xp, __pte_ma(0));
return pte;
}
#define pte_same(a, b) ((a).pte == (b).pte)
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PUD_SIZE (1UL << PUD_SHIFT)
#define PUD_MASK (~(PUD_SIZE-1))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_PGD_NR 0
#ifndef __ASSEMBLY__
#define MAXMEM 0x3fffffffffffUL
#define VMALLOC_START 0xffffc20000000000UL
#define VMALLOC_END 0xffffe1ffffffffffUL
#define MODULES_VADDR 0xffffffff88000000UL
#define MODULES_END 0xfffffffffff00000UL
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
#define _PAGE_BIT_PRESENT 0
#define _PAGE_BIT_RW 1
#define _PAGE_BIT_USER 2
#define _PAGE_BIT_PWT 3
#define _PAGE_BIT_PCD 4
#define _PAGE_BIT_ACCESSED 5
#define _PAGE_BIT_DIRTY 6
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
#define _PAGE_PRESENT 0x001
#define _PAGE_RW 0x002
#define _PAGE_USER 0x004
#define _PAGE_PWT 0x008
#define _PAGE_PCD 0x010
#define _PAGE_ACCESSED 0x020
#define _PAGE_DIRTY 0x040
#define _PAGE_PSE 0x080 /* 2MB page */
#define _PAGE_FILE 0x040 /* set:pagecache, unset:swap */
#define _PAGE_GLOBAL 0x100 /* Global TLB entry */
#define _PAGE_PROTNONE 0x080 /* If not present */
#define _PAGE_NX (1UL<<_PAGE_BIT_NX)
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE _PAGE_TABLE
#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_COPY PAGE_COPY_NOEXEC
#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | _PAGE_USER )
#define __PAGE_KERNEL_EXEC \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_USER )
#define __PAGE_KERNEL_NOCACHE \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX | _PAGE_USER )
#define __PAGE_KERNEL_RO \
(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | _PAGE_USER )
#define __PAGE_KERNEL_VSYSCALL \
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_USER )
#define __PAGE_KERNEL_VSYSCALL_NOCACHE \
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD | _PAGE_USER )
#define __PAGE_KERNEL_LARGE \
(__PAGE_KERNEL | _PAGE_PSE | _PAGE_USER )
/*
* We don't support GLOBAL page in xenolinux64
*/
#define MAKE_GLOBAL(x) __pgprot((x))
#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
#define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
#define PAGE_KERNEL_VSYSCALL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL_NOCACHE)
/* xwr */
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
#define __P010 PAGE_COPY
#define __P011 PAGE_COPY
#define __P100 PAGE_READONLY_EXEC
#define __P101 PAGE_READONLY_EXEC
#define __P110 PAGE_COPY_EXEC
#define __P111 PAGE_COPY_EXEC
#define __S000 PAGE_NONE
#define __S001 PAGE_READONLY
#define __S010 PAGE_SHARED
#define __S011 PAGE_SHARED
#define __S100 PAGE_READONLY_EXEC
#define __S101 PAGE_READONLY_EXEC
#define __S110 PAGE_SHARED_EXEC
#define __S111 PAGE_SHARED_EXEC
static inline unsigned long pgd_bad(pgd_t pgd)
{
unsigned long val = pgd_val(pgd);
val &= ~PTE_MASK;
val &= ~(_PAGE_USER | _PAGE_DIRTY);
return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED);
}
static inline unsigned long pud_bad(pud_t pud)
{
unsigned long val = pud_val(pud);
val &= ~PTE_MASK;
val &= ~(_PAGE_USER | _PAGE_DIRTY);
return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED);
}
#define pte_none(x) (!(x).pte)
#define pte_present(x) ((x).pte & (_PAGE_PRESENT | _PAGE_PROTNONE))
#define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
/*
* We detect special mappings in one of two ways:
* 1. If the MFN is an I/O page then Xen will set the m2p entry
* to be outside our maximum possible pseudophys range.
* 2. If the MFN belongs to a different domain then we will certainly
* not have MFN in our p2m table. Conversely, if the page is ours,
* then we'll have p2m(m2p(MFN))==MFN.
* If we detect a special mapping then it doesn't have a 'struct page'.
* We force !pfn_valid() by returning an out-of-range pointer.
*
* NB. These checks require that, for any MFN that is not in our reservation,
* there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
* we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
* Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
*
* NB2. When deliberately mapping foreign pages into the p2m table, you *must*
* use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
* require. In all the cases we care about, the high bit gets shifted out
* (e.g., phys_to_machine()) so behaviour there is correct.
*/
#define INVALID_P2M_ENTRY (~0UL)
#define FOREIGN_FRAME(_m) ((_m) | (1UL<<((sizeof(unsigned long)*8)-1)))
#define pte_pfn(_pte) \
({ \
unsigned long mfn = (_pte).pte >> PAGE_SHIFT; \
unsigned pfn = mfn_to_pfn(mfn); \
if ((pfn >= max_mapnr) || (pfn_to_mfn(pfn) != mfn)) \
pfn = max_mapnr; /* special: force !pfn_valid() */ \
pfn; \
})
#define pte_page(x) pfn_to_page(pte_pfn(x))
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
pte_t pte;
(pte).pte = (pfn_to_mfn(page_nr) << PAGE_SHIFT);
(pte).pte |= pgprot_val(pgprot);
(pte).pte &= __supported_pte_mask;
return pte;
}
#define pfn_pte_ma(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
#define __pte_val(x) ((x).pte)
static inline int pte_user(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
extern inline int pte_read(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
extern inline int pte_exec(pte_t pte) { return __pte_val(pte) & _PAGE_USER; }
extern inline int pte_dirty(pte_t pte) { return __pte_val(pte) & _PAGE_DIRTY; }
extern inline int pte_young(pte_t pte) { return __pte_val(pte) & _PAGE_ACCESSED; }
extern inline int pte_write(pte_t pte) { return __pte_val(pte) & _PAGE_RW; }
static inline int pte_file(pte_t pte) { return __pte_val(pte) & _PAGE_FILE; }
extern inline pte_t pte_rdprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; }
extern inline pte_t pte_exprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { __pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
extern inline pte_t pte_mkold(pte_t pte) { __pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
extern inline pte_t pte_wrprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_RW; return pte; }
extern inline pte_t pte_mkread(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; }
extern inline pte_t pte_mkexec(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { __pte_val(pte) |= _PAGE_DIRTY; return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { __pte_val(pte) |= _PAGE_ACCESSED; return pte; }
extern inline pte_t pte_mkwrite(pte_t pte) { __pte_val(pte) |= _PAGE_RW; return pte; }
static inline int ptep_test_and_clear_dirty(pte_t *ptep)
{
pte_t pte = *ptep;
int ret = pte_dirty(pte);
if (ret)
xen_l1_entry_update(ptep, pte_mkclean(pte).pte);
return ret;
}
static inline int ptep_test_and_clear_young(pte_t *ptep)
{
pte_t pte = *ptep;
int ret = pte_young(pte);
if (ret)
xen_l1_entry_update(ptep, pte_mkold(pte).pte);
return ret;
}
static inline void ptep_set_wrprotect(pte_t *ptep)
{
pte_t pte = *ptep;
if (pte_write(pte))
set_pte(ptep, pte_wrprotect(pte));
}
static inline void ptep_mkdirty(pte_t *ptep)
{
pte_t pte = *ptep;
if (!pte_dirty(pte))
xen_l1_entry_update(ptep, pte_mkdirty(pte).pte);
}
/*
* Macro to mark a page protection value as "uncacheable".
*/
#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT))
#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
static inline int pmd_large(pmd_t pte) {
return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE;
}
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
#define page_pte(page) page_pte_prot(page, __pgprot(0))
/*
* Level 4 access.
* Never use these in the common code.
*/
#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PTE_MASK))
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
#define pgd_offset_k(address) (pgd_t *)(init_level4_pgt + pgd_index(address))
#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT)
#define mk_kernel_pgd(address) __pgd((address) | _KERNPG_TABLE)
/* PUD - Level3 access */
/* to find an entry in a page-table-directory. */
#define pud_index(address) ((address >> PUD_SHIFT) & (PTRS_PER_PUD-1))
#define pud_offset(pgd, address) ((pud_t *) pgd_page(*(pgd)) + pud_index(address))
static inline pud_t *__pud_offset_k(pud_t *pud, unsigned long address)
{
return pud + pud_index(address);
}
/* Find correct pud via the hidden fourth level page level: */
/* This accesses the reference page table of the boot cpu.
Other CPUs get synced lazily via the page fault handler. */
static inline pud_t *pud_offset_k(unsigned long address)
{
unsigned long addr;
addr = pud_val(init_level4_pgt[pud_index(address)]);
addr &= PHYSICAL_PAGE_MASK; /* machine physical */
addr = machine_to_phys(addr);
return __pud_offset_k((pud_t *)__va(addr), address);
}
/* PMD - Level 2 access */
#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
#define pmd_offset(dir, address) ((pmd_t *) pud_page(*(dir)) + \
pmd_index(address))
#define pmd_none(x) (!pmd_val(x))
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
#define pmd_bad(x) ((pmd_val(x) & ~PTE_MASK) != _KERNPG_TABLE )
#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
#define pmd_pfn(x) ((pmd_val(x) >> PAGE_SHIFT) & __PHYSICAL_MASK)
#define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE })
#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT
/* PTE - Level 1 access. */
/* page, protection -> pte */
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
#define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE)
/* physical address -> PTE */
static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
{
pte_t pte;
(pte).pte = physpage | pgprot_val(pgprot);
return pte;
}
/* Change flags of a PTE */
extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
(pte).pte &= _PAGE_CHG_MASK;
(pte).pte |= pgprot_val(newprot);
(pte).pte &= __supported_pte_mask;
return pte;
}
#define pte_index(address) \
((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
pte_index(address))
/* x86-64 always has all page tables mapped. */
#define pte_offset_map(dir,address) pte_offset_kernel(dir,address)
#define pte_offset_map_nested(dir,address) pte_offset_kernel(dir,address)
#define pte_unmap(pte) /* NOP */
#define pte_unmap_nested(pte) /* NOP */
#define update_mmu_cache(vma,address,pte) do { } while (0)
/* We only update the dirty/accessed state if we set
* the dirty bit by hand in the kernel, since the hardware
* will do the accessed bit for us, and we don't want to
* race with other CPU's that might be updating the dirty
* bit at the same time. */
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
do { \
if (__dirty) { \
set_pte(__ptep, __entry); \
flush_tlb_page(__vma, __address); \
} \
} while (0)
/* Encode and de-code a swap entry */
#define __swp_type(x) (((x).val >> 1) & 0x3f)
#define __swp_offset(x) ((x).val >> 8)
#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
#endif /* !__ASSEMBLY__ */
extern int kern_addr_valid(unsigned long addr);
#define DOMID_LOCAL (0xFFFFU)
int direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long machine_addr,
unsigned long size,
pgprot_t prot,
domid_t domid);
int __direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long size,
mmu_update_t *v);
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
#define HAVE_ARCH_UNMAPPED_AREA
#define pgtable_cache_init() do { } while (0)
#define check_pgt_cache() do { } while (0)
#define PAGE_AGP PAGE_KERNEL_NOCACHE
#define HAVE_PAGE_AGP 1
/* fs/proc/kcore.c */
#define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK)
#define kc_offset_to_vaddr(o) \
(((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o))
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTEP_MKDIRTY
#define __HAVE_ARCH_PTE_SAME
#include <asm-generic/pgtable.h>
#endif /* _X86_64_PGTABLE_H */
@@ -0,0 +1,474 @@
/*
* include/asm-x86_64/processor.h
*
* Copyright (C) 1994 Linus Torvalds
*/
#ifndef __ASM_X86_64_PROCESSOR_H
#define __ASM_X86_64_PROCESSOR_H
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/types.h>
#include <asm/sigcontext.h>
#include <asm/cpufeature.h>
#include <linux/config.h>
#include <linux/threads.h>
#include <asm/msr.h>
#include <asm/current.h>
#include <asm/system.h>
#include <asm/mmsegment.h>
#include <asm/percpu.h>
#include <linux/personality.h>
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define IOPL_MASK 0x00003000
#define NT_MASK 0x00004000
#define VM_MASK 0x00020000
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000 /* virtual interrupt flag */
#define VIP_MASK 0x00100000 /* virtual interrupt pending */
#define ID_MASK 0x00200000
#define desc_empty(desc) \
(!((desc)->a + (desc)->b))
#define desc_equal(desc1, desc2) \
(((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
#define current_text_addr() ({ void *pc; asm volatile("leaq 1f(%%rip),%0\n1:":"=r"(pc)); pc; })
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
*/
struct cpuinfo_x86 {
__u8 x86; /* CPU family */
__u8 x86_vendor; /* CPU vendor */
__u8 x86_model;
__u8 x86_mask;
int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
__u32 x86_capability[NCAPINTS];
char x86_vendor_id[16];
char x86_model_id[64];
int x86_cache_size; /* in KB */
int x86_clflush_size;
int x86_cache_alignment;
int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined(in pages)*/
__u8 x86_virt_bits, x86_phys_bits;
__u8 x86_num_cores;
__u8 x86_apicid;
__u32 x86_power;
__u32 x86_cpuid_level; /* Max CPUID function supported */
unsigned long loops_per_jiffy;
} ____cacheline_aligned;
#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
#define X86_VENDOR_AMD 2
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NUM 8
#define X86_VENDOR_UNKNOWN 0xff
#ifdef CONFIG_SMP
extern struct cpuinfo_x86 cpu_data[];
#define current_cpu_data cpu_data[smp_processor_id()]
#else
#define cpu_data (&boot_cpu_data)
#define current_cpu_data boot_cpu_data
#endif
extern char ignore_irq13;
extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern void dodgy_tsc(void);
/*
* EFLAGS bits
*/
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
/*
* Intel CPU features in CR4
*/
#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
#define X86_CR4_DE 0x0008 /* enable debugging extensions */
#define X86_CR4_PSE 0x0010 /* enable page size extensions */
#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
#define X86_CR4_MCE 0x0040 /* Machine check enable */
#define X86_CR4_PGE 0x0080 /* enable global pages */
#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
/*
* Save the cr4 feature set we're using (ie
* Pentium 4MB enable and PPro Global page
* enable), so that any CPU's that boot up
* after us can get the correct flags.
*/
extern unsigned long mmu_cr4_features;
static inline void set_in_cr4 (unsigned long mask)
{
mmu_cr4_features |= mask;
switch (mask) {
case X86_CR4_OSFXSR:
case X86_CR4_OSXMMEXCPT:
break;
default:
do {
const char *msg = "Xen unsupported cr4 update\n";
(void)HYPERVISOR_console_io(
CONSOLEIO_write, __builtin_strlen(msg),
(char *)msg);
BUG();
} while (0);
}
}
#define load_cr3(pgdir) do { \
xen_pt_switch(__pa(pgdir)); \
per_cpu(cur_pgd, smp_processor_id()) = pgdir; \
} while (/* CONSTCOND */0)
/*
* Bus types
*/
#define MCA_bus 0
#define MCA_bus__is_a_macro
/*
* User space process size. 47bits.
*/
#define TASK_SIZE (0x800000000000UL)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000)
#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3)
#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3)
#define TASK_UNMAPPED_BASE \
(test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)
/*
* Size of io_bitmap.
*/
#define IO_BITMAP_BITS 65536
#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8)
#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long))
#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
#define INVALID_IO_BITMAP_OFFSET 0x8000
struct i387_fxsave_struct {
u16 cwd;
u16 swd;
u16 twd;
u16 fop;
u64 rip;
u64 rdp;
u32 mxcsr;
u32 mxcsr_mask;
u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 128 bytes */
u32 padding[24];
} __attribute__ ((aligned (16)));
union i387_union {
struct i387_fxsave_struct fxsave;
};
struct tss_struct {
u32 reserved1;
u64 rsp0;
u64 rsp1;
u64 rsp2;
u64 reserved2;
u64 ist[7];
u32 reserved3;
u32 reserved4;
u16 reserved5;
u16 io_bitmap_base;
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
* bitmap. The extra byte must be all 1 bits, and must
* be within the limit. Thus we have:
*
* 128 bytes, the bitmap itself, for ports 0..0x3ff
* 8 bytes, for an extra "long" of ~0UL
*/
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
} __attribute__((packed)) ____cacheline_aligned;
extern struct cpuinfo_x86 boot_cpu_data;
DECLARE_PER_CPU(struct tss_struct,init_tss);
DECLARE_PER_CPU(pgd_t *, cur_pgd);
#define ARCH_MIN_TASKALIGN 16
struct thread_struct {
unsigned long rsp0;
unsigned long rsp;
unsigned long userrsp; /* Copy from PDA */
unsigned long fs;
unsigned long gs;
unsigned int io_pl;
unsigned short es, ds, fsindex, gsindex;
/* Hardware debugging registers */
unsigned long debugreg0;
unsigned long debugreg1;
unsigned long debugreg2;
unsigned long debugreg3;
unsigned long debugreg6;
unsigned long debugreg7;
/* fault info */
unsigned long cr2, trap_no, error_code;
/* floating point info */
union i387_union i387 __attribute__((aligned(16)));
/* IO permissions. the bitmap could be moved into the GDT, that would make
switch faster for a limited number of ioperm using tasks. -AK */
int ioperm;
unsigned long *io_bitmap_ptr;
unsigned io_bitmap_max;
/* cached TLS descriptors. */
u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
} __attribute__((aligned(16)));
#define INIT_THREAD {}
#define INIT_MMAP \
{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
#define STACKFAULT_STACK 1
#define DOUBLEFAULT_STACK 2
#define NMI_STACK 3
#define DEBUG_STACK 4
#define MCE_STACK 5
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
#define EXCEPTION_STACK_ORDER 0
#define start_thread(regs,new_rip,new_rsp) do { \
asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0)); \
load_gs_index(0); \
(regs)->rip = (new_rip); \
(regs)->rsp = (new_rsp); \
write_pda(oldrsp, (new_rsp)); \
(regs)->cs = __USER_CS; \
(regs)->ss = __USER_DS; \
(regs)->eflags = 0x200; \
set_fs(USER_DS); \
} while(0)
struct task_struct;
struct mm_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
/* Prepare to copy thread state - unlazy all lazy status */
extern void prepare_to_copy(struct task_struct *tsk);
/*
* create a kernel thread without removing it from tasklists
*/
extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
/*
* Return saved PC of a blocked thread.
* What is this good for? it will be always the scheduler or ret_from_fork.
*/
#define thread_saved_pc(t) (*(unsigned long *)((t)->thread.rsp - 8))
extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) \
(((struct pt_regs *)(tsk->thread.rsp0 - sizeof(struct pt_regs)))->rip)
#define KSTK_ESP(tsk) -1 /* sorry. doesn't work for syscall. */
struct microcode_header {
unsigned int hdrver;
unsigned int rev;
unsigned int date;
unsigned int sig;
unsigned int cksum;
unsigned int ldrver;
unsigned int pf;
unsigned int datasize;
unsigned int totalsize;
unsigned int reserved[3];
};
struct microcode {
struct microcode_header hdr;
unsigned int bits[0];
};
typedef struct microcode microcode_t;
typedef struct microcode_header microcode_header_t;
/* microcode format is extended from prescott processors */
struct extended_signature {
unsigned int sig;
unsigned int pf;
unsigned int cksum;
};
struct extended_sigtable {
unsigned int count;
unsigned int cksum;
unsigned int reserved[3];
struct extended_signature sigs[0];
};
/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
#define MICROCODE_IOCFREE _IO('6',0)
#define ASM_NOP1 K8_NOP1
#define ASM_NOP2 K8_NOP2
#define ASM_NOP3 K8_NOP3
#define ASM_NOP4 K8_NOP4
#define ASM_NOP5 K8_NOP5
#define ASM_NOP6 K8_NOP6
#define ASM_NOP7 K8_NOP7
#define ASM_NOP8 K8_NOP8
/* Opteron nops */
#define K8_NOP1 ".byte 0x90\n"
#define K8_NOP2 ".byte 0x66,0x90\n"
#define K8_NOP3 ".byte 0x66,0x66,0x90\n"
#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"
#define K8_NOP5 K8_NOP3 K8_NOP2
#define K8_NOP6 K8_NOP3 K8_NOP3
#define K8_NOP7 K8_NOP4 K8_NOP3
#define K8_NOP8 K8_NOP4 K8_NOP4
#define ASM_NOP_MAX 8
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
extern inline void rep_nop(void)
{
__asm__ __volatile__("rep;nop": : :"memory");
}
/* Stop speculative execution */
extern inline void sync_core(void)
{
int tmp;
asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
}
#define cpu_has_fpu 1
#define ARCH_HAS_PREFETCH
static inline void prefetch(void *x)
{
asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
}
#define ARCH_HAS_PREFETCHW 1
static inline void prefetchw(void *x)
{
alternative_input(ASM_NOP5,
"prefetchw (%1)",
X86_FEATURE_3DNOW,
"r" (x));
}
#define ARCH_HAS_SPINLOCK_PREFETCH 1
#define spin_lock_prefetch(x) prefetchw(x)
#define cpu_relax() rep_nop()
/*
* NSC/Cyrix CPU configuration register indexes
*/
#define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1
#define CX86_CCR2 0xc2
#define CX86_CCR3 0xc3
#define CX86_CCR4 0xe8
#define CX86_CCR5 0xe9
#define CX86_CCR6 0xea
#define CX86_CCR7 0xeb
#define CX86_DIR0 0xfe
#define CX86_DIR1 0xff
#define CX86_ARR_BASE 0xc4
#define CX86_RCR_BASE 0xdc
/*
* NSC/Cyrix CPU indexed register access macros
*/
#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
#define setCx86(reg, data) do { \
outb((reg), 0x22); \
outb((data), 0x23); \
} while (0)
static inline void __monitor(const void *eax, unsigned long ecx,
unsigned long edx)
{
/* "monitor %eax,%ecx,%edx;" */
asm volatile(
".byte 0x0f,0x01,0xc8;"
: :"a" (eax), "c" (ecx), "d"(edx));
}
static inline void __mwait(unsigned long eax, unsigned long ecx)
{
/* "mwait %eax,%ecx;" */
asm volatile(
".byte 0x0f,0x01,0xc9;"
: :"a" (eax), "c" (ecx));
}
#define stack_current() \
({ \
struct thread_info *ti; \
asm("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \
ti->task; \
})
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
extern unsigned long boot_option_idle_override;
/* Boot loader type from the setup header */
extern int bootloader_type;
#endif /* __ASM_X86_64_PROCESSOR_H */
@@ -0,0 +1,119 @@
#ifndef _X86_64_PTRACE_H
#define _X86_64_PTRACE_H
#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
#define R15 0
#define R14 8
#define R13 16
#define R12 24
#define RBP 32
#define RBX 40
/* arguments: interrupts/non tracing syscalls only save upto here*/
#define R11 48
#define R10 56
#define R9 64
#define R8 72
#define RAX 80
#define RCX 88
#define RDX 96
#define RSI 104
#define RDI 112
#define ORIG_RAX 120 /* = ERROR */
/* end of arguments */
/* cpu exception frame or undefined in case of fast syscall. */
#define RIP 128
#define CS 136
#define EFLAGS 144
#define RSP 152
#define SS 160
#define ARGOFFSET R11
#endif /* __ASSEMBLY__ */
/* top of stack page */
#define FRAME_SIZE 168
#define PTRACE_OLDSETOPTIONS 21
#ifndef __ASSEMBLY__
struct pt_regs {
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long rbp;
unsigned long rbx;
/* arguments: non interrupts/non tracing syscalls only save upto here*/
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long rax;
unsigned long rcx;
unsigned long rdx;
unsigned long rsi;
unsigned long rdi;
unsigned long orig_rax;
/* end of arguments */
/* cpu exception frame or undefined */
unsigned long rip;
unsigned long cs;
unsigned long eflags;
unsigned long rsp;
unsigned long ss;
/* top of stack page */
};
#endif
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
#define PTRACE_GETFPXREGS 18
#define PTRACE_SETFPXREGS 19
/* only useful for access 32bit programs */
#define PTRACE_GET_THREAD_AREA 25
#define PTRACE_SET_THREAD_AREA 26
#define PTRACE_ARCH_PRCTL 30 /* arch_prctl for child */
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
#define user_mode(regs) (!!((regs)->cs & 3))
#define instruction_pointer(regs) ((regs)->rip)
#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
extern unsigned long profile_pc(struct pt_regs *regs);
#else
#define profile_pc(regs) instruction_pointer(regs)
#endif
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
enum {
EF_CF = 0x00000001,
EF_PF = 0x00000004,
EF_AF = 0x00000010,
EF_ZF = 0x00000040,
EF_SF = 0x00000080,
EF_TF = 0x00000100,
EF_IE = 0x00000200,
EF_DF = 0x00000400,
EF_OF = 0x00000800,
EF_IOPL = 0x00003000,
EF_IOPL_RING0 = 0x00000000,
EF_IOPL_RING1 = 0x00001000,
EF_IOPL_RING2 = 0x00002000,
EF_NT = 0x00004000, /* nested task */
EF_RF = 0x00010000, /* resume */
EF_VM = 0x00020000, /* virtual mode */
EF_AC = 0x00040000, /* alignment */
EF_VIF = 0x00080000, /* virtual interrupt */
EF_VIP = 0x00100000, /* virtual interrupt pending */
EF_ID = 0x00200000, /* id */
};
#endif
#endif
@@ -0,0 +1,47 @@
#ifndef _ASM_SEGMENT_H
#define _ASM_SEGMENT_H
#include <asm/cache.h>
#define __KERNEL_CS 0x10
#define __KERNEL_DS 0x1b
#define __KERNEL32_CS 0x3b
/*
* we cannot use the same code segment descriptor for user and kernel
* -- not even in the long flat mode, because of different DPL /kkeil
* The segment offset needs to contain a RPL. Grr. -AK
* GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets)
*/
#define __USER32_CS 0x23 /* 4*8+3 */
#define __USER_DS 0x2b /* 5*8+3 */
#define __USER_CS 0x33 /* 6*8+3 */
#define __USER32_DS __USER_DS
#define __KERNEL16_CS (GDT_ENTRY_KERNELCS16 * 8)
#define __KERNEL_COMPAT32_CS 0x8
#define GDT_ENTRY_TLS 1
#define GDT_ENTRY_TSS 8 /* needs two entries */
#define GDT_ENTRY_LDT 10
#define GDT_ENTRY_TLS_MIN 11
#define GDT_ENTRY_TLS_MAX 13
/* 14 free */
#define GDT_ENTRY_KERNELCS16 15
#define GDT_ENTRY_TLS_ENTRIES 3
/* TLS indexes for 64bit - hardcoded in arch_prctl */
#define FS_TLS 0
#define GS_TLS 1
#define GS_TLS_SEL ((GDT_ENTRY_TLS_MIN+GS_TLS)*8 + 3)
#define FS_TLS_SEL ((GDT_ENTRY_TLS_MIN+FS_TLS)*8 + 3)
#define IDT_ENTRIES 256
#define GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY + 1)
#define GDT_SIZE (GDT_ENTRIES * 8)
#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
#endif
@@ -0,0 +1,154 @@
#ifndef __ASM_SMP_H
#define __ASM_SMP_H
/*
* We need the APIC definitions automatically as part of 'smp.h'
*/
#ifndef __ASSEMBLY__
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/bitops.h>
extern int disable_apic;
#endif
#ifdef CONFIG_X86_LOCAL_APIC
#ifndef __ASSEMBLY__
#include <asm/fixmap.h>
#include <asm/mpspec.h>
#ifdef CONFIG_X86_IO_APIC
#include <asm/io_apic.h>
#endif
#include <asm/apic.h>
#include <asm/thread_info.h>
#endif
#endif
#ifdef CONFIG_SMP
#ifndef ASSEMBLY
#include <asm/pda.h>
struct pt_regs;
/*
* Private routines/data
*/
extern void smp_alloc_memory(void);
extern cpumask_t cpu_online_map;
extern volatile unsigned long smp_invalidate_needed;
extern int pic_mode;
extern int smp_num_siblings;
extern void smp_flush_tlb(void);
extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
extern void smp_send_reschedule(int cpu);
extern void smp_invalidate_rcv(void); /* Process an NMI */
extern void (*mtrr_hook) (void);
extern void zap_low_mappings(void);
void smp_stop_cpu(void);
extern cpumask_t cpu_sibling_map[NR_CPUS];
extern u8 phys_proc_id[NR_CPUS];
#define SMP_TRAMPOLINE_BASE 0x6000
/*
* On x86 all CPUs are mapped 1:1 to the APIC space.
* This simplifies scheduling and IPI sending and
* compresses data structures.
*/
extern cpumask_t cpu_callout_map;
extern cpumask_t cpu_callin_map;
#define cpu_possible_map cpu_callout_map
static inline int num_booting_cpus(void)
{
return cpus_weight(cpu_callout_map);
}
#define __smp_processor_id() read_pda(cpunumber)
#ifdef CONFIG_X86_LOCAL_APIC
extern __inline int hard_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
}
#endif
#define safe_smp_processor_id() (disable_apic ? 0 : x86_apicid_to_cpu(hard_smp_processor_id()))
#endif /* !ASSEMBLY */
#define NO_PROC_ID 0xFF /* No processor magic marker */
#endif
#ifndef ASSEMBLY
/*
* Some lowlevel functions might want to know about
* the real APIC ID <-> CPU # mapping.
*/
extern u8 x86_cpu_to_apicid[NR_CPUS]; /* physical ID */
extern u8 x86_cpu_to_log_apicid[NR_CPUS];
extern u8 bios_cpu_apicid[];
#ifdef CONFIG_X86_LOCAL_APIC
static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
{
return cpus_addr(cpumask)[0];
}
static inline int x86_apicid_to_cpu(u8 apicid)
{
int i;
for (i = 0; i < NR_CPUS; ++i)
if (x86_cpu_to_apicid[i] == apicid)
return i;
/* No entries in x86_cpu_to_apicid? Either no MPS|ACPI,
* or called too early. Either way, we must be CPU 0. */
if (x86_cpu_to_apicid[0] == BAD_APICID)
return 0;
return -1;
}
static inline int cpu_present_to_apicid(int mps_cpu)
{
if (mps_cpu < NR_CPUS)
return (int)bios_cpu_apicid[mps_cpu];
else
return BAD_APICID;
}
#endif
#endif /* !ASSEMBLY */
#ifndef CONFIG_SMP
#define stack_smp_processor_id() 0
#define safe_smp_processor_id() 0
#define cpu_logical_map(x) (x)
#else
#include <asm/thread_info.h>
#define stack_smp_processor_id() \
({ \
struct thread_info *ti; \
__asm__("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \
ti->cpu; \
})
#endif
#ifndef __ASSEMBLY__
#ifdef CONFIG_X86_LOCAL_APIC
static __inline int logical_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
}
#endif
#endif
#endif
@@ -0,0 +1,85 @@
#ifndef __XEN_SYNCH_BITOPS_H__
#define __XEN_SYNCH_BITOPS_H__
/*
* Copyright 1992, Linus Torvalds.
* Heavily modified to provide guaranteed strong synchronisation
* when communicating with Xen or other guest OSes running on other CPUs.
*
* Copyed from asm-xen/asm-i386
*/
#include <linux/config.h>
#define ADDR (*(volatile long *) addr)
static __inline__ void synch_set_bit(int nr, volatile void * addr)
{
__asm__ __volatile__ (
"lock btsl %1,%0"
: "=m" (ADDR) : "Ir" (nr) : "memory" );
}
static __inline__ void synch_clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__ (
"lock btrl %1,%0"
: "=m" (ADDR) : "Ir" (nr) : "memory" );
}
static __inline__ void synch_change_bit(int nr, volatile void * addr)
{
__asm__ __volatile__ (
"lock btcl %1,%0"
: "=m" (ADDR) : "Ir" (nr) : "memory" );
}
static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__ (
"lock btsl %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "=m" (ADDR) : "Ir" (nr) : "memory");
return oldbit;
}
static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__ (
"lock btrl %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "=m" (ADDR) : "Ir" (nr) : "memory");
return oldbit;
}
static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__ (
"lock btcl %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "=m" (ADDR) : "Ir" (nr) : "memory");
return oldbit;
}
static __inline__ int synch_const_test_bit(int nr, const volatile void * addr)
{
return ((1UL << (nr & 31)) &
(((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__ (
"btl %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit) : "m" (ADDR), "Ir" (nr) );
return oldbit;
}
#define synch_test_bit(nr,addr) \
(__builtin_constant_p(nr) ? \
synch_const_test_bit((nr),(addr)) : \
synch_var_test_bit((nr),(addr)))
#endif /* __XEN_SYNCH_BITOPS_H__ */
@@ -0,0 +1,405 @@
#ifndef __ASM_SYSTEM_H
#define __ASM_SYSTEM_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/synch_bitops.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/xen-public/arch-x86_64.h>
#ifdef __KERNEL__
#ifdef CONFIG_SMP
#define LOCK_PREFIX "lock ; "
#else
#define LOCK_PREFIX ""
#endif
#define __STR(x) #x
#define STR(x) __STR(x)
#define __SAVE(reg,offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t"
#define __RESTORE(reg,offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
/* frame pointer must be last for get_wchan */
#define SAVE_CONTEXT "pushfq ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popfq\n\t"
#define __EXTRA_CLOBBER \
,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15"
#define switch_to(prev,next,last) \
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
"movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
"call __switch_to\n\t" \
".globl thread_return\n" \
"thread_return:\n\t" \
"movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \
"movq %P[thread_info](%%rsi),%%r8\n\t" \
LOCK "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \
"movq %%rax,%%rdi\n\t" \
"jc ret_from_fork\n\t" \
RESTORE_CONTEXT \
: "=a" (last) \
: [next] "S" (next), [prev] "D" (prev), \
[threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
[ti_flags] "i" (offsetof(struct thread_info, flags)),\
[tif_fork] "i" (TIF_FORK), \
[thread_info] "i" (offsetof(struct task_struct, thread_info)), \
[pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \
: "memory", "cc" __EXTRA_CLOBBER)
extern void load_gs_index(unsigned);
#define __load_gs_index(index) \
xen_load_gs((index))
/*
* Load a segment. Fall back on loading the zero
* segment if something goes wrong..
*/
#define loadsegment(seg,value) \
asm volatile("\n" \
"1:\t" \
"movl %k0,%%" #seg "\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3:\t" \
"movl %1,%%" #seg "\n\t" \
"jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n\t" \
".align 8\n\t" \
".quad 1b,3b\n" \
".previous" \
: :"r" (value), "r" (0))
#define set_debug(value,register) \
__asm__("movq %0,%%db" #register \
: /* no output */ \
:"r" ((unsigned long) value))
#ifdef __KERNEL__
struct alt_instr {
__u8 *instr; /* original instruction */
__u8 *replacement;
__u8 cpuid; /* cpuid bit set for replacement */
__u8 instrlen; /* length of original instruction */
__u8 replacementlen; /* length of new instruction, <= instrlen */
__u8 pad[5];
};
#endif
/*
* Alternative instructions for different CPU types or capabilities.
*
* This allows to use optimized instructions even on generic binary
* kernels.
*
* length of oldinstr must be longer or equal the length of newinstr
* It can be padded with nops as needed.
*
* For non barrier like inlines please define new variants
* without volatile and memory clobber.
*/
#define alternative(oldinstr, newinstr, feature) \
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
".section .altinstructions,\"a\"\n" \
" .align 8\n" \
" .quad 661b\n" /* label */ \
" .quad 663f\n" /* new instruction */ \
" .byte %c0\n" /* feature bit */ \
" .byte 662b-661b\n" /* sourcelen */ \
" .byte 664f-663f\n" /* replacementlen */ \
".previous\n" \
".section .altinstr_replacement,\"ax\"\n" \
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
".previous" :: "i" (feature) : "memory")
/*
* Alternative inline assembly with input.
*
* Pecularities:
* No memory clobber here.
* Argument numbers start with 1.
* Best is to use constraints that are fixed size (like (%1) ... "r")
* If you use variable sized constraints like "m" or "g" in the
* replacement maake sure to pad to the worst case length.
*/
#define alternative_input(oldinstr, newinstr, feature, input...) \
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
".section .altinstructions,\"a\"\n" \
" .align 8\n" \
" .quad 661b\n" /* label */ \
" .quad 663f\n" /* new instruction */ \
" .byte %c0\n" /* feature bit */ \
" .byte 662b-661b\n" /* sourcelen */ \
" .byte 664f-663f\n" /* replacementlen */ \
".previous\n" \
".section .altinstr_replacement,\"ax\"\n" \
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
".previous" :: "i" (feature), ##input)
/*
* Clear and set 'TS' bit respectively
*/
#define clts() __asm__ __volatile__ ("clts")
static inline unsigned long read_cr0(void)
{
BUG();
}
static inline void write_cr0(unsigned long val)
{
BUG();
}
static inline unsigned long read_cr3(void)
{
BUG();
}
static inline unsigned long read_cr4(void)
{
BUG();
}
static inline void write_cr4(unsigned long val)
{
BUG();
}
#define stts() write_cr0(8 | read_cr0())
static inline void wbinvd(void)
{
mmu_update_t u;
u.ptr = MMU_EXTENDED_COMMAND;
u.val = MMUEXT_FLUSH_CACHE;
(void)HYPERVISOR_mmu_update(&u, 1, NULL);
}
#endif /* __KERNEL__ */
#define nop() __asm__ __volatile__ ("nop")
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
#define tas(ptr) (xchg((ptr),1))
#define __xg(x) ((volatile long *)(x))
extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
{
*ptr = val;
}
#define _set_64bit set_64bit
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
* Note 2: xchg has side effect, so that attribute volatile is necessary,
* but generally the primitive is invalid, *ptr is output argument. --ANK
*/
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 1:
__asm__ __volatile__("xchgb %b0,%1"
:"=q" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 2:
__asm__ __volatile__("xchgw %w0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 4:
__asm__ __volatile__("xchgl %k0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 8:
__asm__ __volatile__("xchgq %0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
}
return x;
}
/*
* Atomic compare and exchange. Compare OLD with MEM, if identical,
* store NEW in MEM. Return the initial value in MEM. Success is
* indicated by comparing RETURN with OLD.
*/
#define __HAVE_ARCH_CMPXCHG 1
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
unsigned long prev;
switch (size) {
case 1:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 2:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 4:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 8:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
}
return old;
}
#define cmpxchg(ptr,o,n)\
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#define smp_read_barrier_depends() do {} while(0)
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do {} while(0)
#endif
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
* to devices.
*/
#define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory")
#ifdef CONFIG_UNORDERED_IO
#define wmb() asm volatile("sfence" ::: "memory")
#else
#define wmb() asm volatile("" ::: "memory")
#endif
#define read_barrier_depends() do {} while(0)
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
/*
* The use of 'barrier' in the following reflects their use as local-lock
* operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
* critical operations are executed. All critical operations must complete
* /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
* includes these barriers, for example.
*/
#define __cli() \
do { \
vcpu_info_t *_vcpu; \
preempt_disable(); \
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
_vcpu->evtchn_upcall_mask = 1; \
preempt_enable_no_resched(); \
barrier(); \
} while (0)
#define __sti() \
do { \
vcpu_info_t *_vcpu; \
barrier(); \
preempt_disable(); \
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
_vcpu->evtchn_upcall_mask = 0; \
barrier(); /* unmask then check (avoid races) */ \
if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
force_evtchn_callback(); \
preempt_enable(); \
} while (0)
#define __save_flags(x) \
do { \
vcpu_info_t *_vcpu; \
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
(x) = _vcpu->evtchn_upcall_mask; \
} while (0)
#define __restore_flags(x) \
do { \
vcpu_info_t *_vcpu; \
barrier(); \
preempt_disable(); \
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \
barrier(); /* unmask then check (avoid races) */ \
if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
force_evtchn_callback(); \
preempt_enable(); \
} else \
preempt_enable_no_resched(); \
} while (0)
#define safe_halt() ((void)0)
#define __save_and_cli(x) \
do { \
vcpu_info_t *_vcpu; \
preempt_disable(); \
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
(x) = _vcpu->evtchn_upcall_mask; \
_vcpu->evtchn_upcall_mask = 1; \
preempt_enable_no_resched(); \
barrier(); \
} while (0)
void cpu_idle_wait(void);
#define local_irq_save(x) __save_and_cli(x)
#define local_irq_restore(x) __restore_flags(x)
#define local_save_flags(x) __save_flags(x)
#define local_irq_disable() __cli()
#define local_irq_enable() __sti()
#define irqs_disabled() \
HYPERVISOR_shared_info->vcpu_data[smp_processor_id()].evtchn_upcall_mask
/*
* disable hlt during certain critical i/o operations
*/
#define HAVE_DISABLE_HLT
void disable_hlt(void);
void enable_hlt(void);
#define HAVE_EAT_KEY
void eat_key(void);
#endif
@@ -0,0 +1,64 @@
#ifndef _ASMi386_TIMER_H
#define _ASMi386_TIMER_H
#include <linux/init.h>
/**
* struct timer_ops - used to define a timer source
*
* @name: name of the timer.
* @init: Probes and initializes the timer. Takes clock= override
* string as an argument. Returns 0 on success, anything else
* on failure.
* @mark_offset: called by the timer interrupt.
* @get_offset: called by gettimeofday(). Returns the number of microseconds
* since the last timer interupt.
* @monotonic_clock: returns the number of nanoseconds since the init of the
* timer.
* @delay: delays this many clock cycles.
*/
struct timer_opts {
char* name;
void (*mark_offset)(void);
unsigned long (*get_offset)(void);
unsigned long long (*monotonic_clock)(void);
void (*delay)(unsigned long);
};
struct init_timer_opts {
int (*init)(char *override);
struct timer_opts *opts;
};
#define TICK_SIZE (tick_nsec / 1000)
extern struct timer_opts* __init select_timer(void);
extern void clock_fallback(void);
void setup_pit_timer(void);
/* Modifiers for buggy PIT handling */
extern int pit_latch_buggy;
extern struct timer_opts *cur_timer;
extern int timer_ack;
/* list of externed timers */
extern struct timer_opts timer_none;
extern struct timer_opts timer_pit;
extern struct init_timer_opts timer_pit_init;
extern struct init_timer_opts timer_tsc_init;
#ifdef CONFIG_X86_CYCLONE_TIMER
extern struct init_timer_opts timer_cyclone_init;
#endif
extern unsigned long calibrate_tsc(void);
extern void init_cpu_khz(void);
#ifdef CONFIG_HPET_TIMER
extern struct init_timer_opts timer_hpet_init;
extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
#endif
#ifdef CONFIG_X86_PM_TIMER
extern struct init_timer_opts timer_pmtmr_init;
#endif
#endif
@@ -0,0 +1,97 @@
#ifndef _X8664_TLBFLUSH_H
#define _X8664_TLBFLUSH_H
#include <linux/config.h>
#include <linux/mm.h>
#include <asm/processor.h>
#define __flush_tlb() xen_tlb_flush()
/*
* Global pages have to be flushed a bit differently. Not a real
* performance problem because this does not happen often.
*/
#define __flush_tlb_global() xen_tlb_flush()
extern unsigned long pgkern_mask;
#define __flush_tlb_all() __flush_tlb_global()
#define __flush_tlb_one(addr) xen_invlpg(addr)
/*
* TLB flushing:
*
* - flush_tlb() flushes the current mm struct TLBs
* - flush_tlb_all() flushes all processes TLBs
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(vma, start, end) flushes a range of pages
* - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
* - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
*
* ..but the x86_64 has somewhat limited tlb flushing capabilities,
* and page-granular flushes are available only on i486 and up.
*/
#ifndef CONFIG_SMP
#define flush_tlb() __flush_tlb()
#define flush_tlb_all() __flush_tlb_all()
#define local_flush_tlb() __flush_tlb()
static inline void flush_tlb_mm(struct mm_struct *mm)
{
if (mm == current->active_mm)
__flush_tlb();
}
static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr)
{
if (vma->vm_mm == current->active_mm)
__flush_tlb_one(addr);
}
static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
if (vma->vm_mm == current->active_mm)
__flush_tlb();
}
#else
#include <asm/smp.h>
#define local_flush_tlb() \
__flush_tlb()
extern void flush_tlb_all(void);
extern void flush_tlb_current_task(void);
extern void flush_tlb_mm(struct mm_struct *);
extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
#define flush_tlb() flush_tlb_current_task()
static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
{
flush_tlb_mm(vma->vm_mm);
}
#define TLBSTATE_OK 1
#define TLBSTATE_LAZY 2
#endif
#define flush_tlb_kernel_range(start, end) flush_tlb_all()
static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
/* x86_64 does not keep any page table caches in TLB */
}
#endif /* _X8664_TLBFLUSH_H */
@@ -0,0 +1,20 @@
/*
* Access to VGA videoram
*
* (c) 1998 Martin Mares <mj@ucw.cz>
*/
#ifndef _LINUX_ASM_VGA_H_
#define _LINUX_ASM_VGA_H_
/*
* On the PC, we can just recalculate addresses and then
* access the videoram directly without any black magic.
*/
#define VGA_MAP_MEM(x) (unsigned long)isa_bus_to_virt(x)
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
#endif
@@ -0,0 +1,328 @@
/*
* x86-64 changes / gcc fixes from Andi Kleen.
* Copyright 2002 Andi Kleen, SuSE Labs.
*
* This hasn't been optimized for the hammer yet, but there are likely
* no advantages to be gotten from x86-64 here anyways.
*/
typedef struct { unsigned long a,b; } __attribute__((aligned(16))) xmm_store_t;
/* Doesn't use gcc to save the XMM registers, because there is no easy way to
tell it to do a clts before the register saving. */
#define XMMS_SAVE do { \
preempt_disable(); \
if (!(current_thread_info()->status & TS_USEDFPU)) \
clts(); \
__asm__ __volatile__ ( \
"movups %%xmm0,(%1) ;\n\t" \
"movups %%xmm1,0x10(%1) ;\n\t" \
"movups %%xmm2,0x20(%1) ;\n\t" \
"movups %%xmm3,0x30(%1) ;\n\t" \
: "=&r" (cr0) \
: "r" (xmm_save) \
: "memory"); \
} while(0)
#define XMMS_RESTORE do { \
asm volatile ( \
"sfence ;\n\t" \
"movups (%1),%%xmm0 ;\n\t" \
"movups 0x10(%1),%%xmm1 ;\n\t" \
"movups 0x20(%1),%%xmm2 ;\n\t" \
"movups 0x30(%1),%%xmm3 ;\n\t" \
: \
: "r" (cr0), "r" (xmm_save) \
: "memory"); \
if (!(current_thread_info()->status & TS_USEDFPU)) \
stts(); \
preempt_enable(); \
} while(0)
#define OFFS(x) "16*("#x")"
#define PF_OFFS(x) "256+16*("#x")"
#define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n"
#define LD(x,y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n"
#define ST(x,y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n"
#define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n"
#define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n"
#define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n"
#define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n"
#define PF5(x) " prefetchnta "PF_OFFS(x)"(%[p6]) ;\n"
#define XO1(x,y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n"
#define XO2(x,y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n"
#define XO3(x,y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n"
#define XO4(x,y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n"
#define XO5(x,y) " xorps "OFFS(x)"(%[p6]), %%xmm"#y" ;\n"
static void
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
{
unsigned int lines = bytes >> 8;
unsigned long cr0;
xmm_store_t xmm_save[4];
XMMS_SAVE;
asm volatile (
#undef BLOCK
#define BLOCK(i) \
LD(i,0) \
LD(i+1,1) \
PF1(i) \
PF1(i+2) \
LD(i+2,2) \
LD(i+3,3) \
PF0(i+4) \
PF0(i+6) \
XO1(i,0) \
XO1(i+1,1) \
XO1(i+2,2) \
XO1(i+3,3) \
ST(i,0) \
ST(i+1,1) \
ST(i+2,2) \
ST(i+3,3) \
PF0(0)
PF0(2)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addq %[inc], %[p1] ;\n"
" addq %[inc], %[p2] ;\n"
" decl %[cnt] ; jnz 1b"
: [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
: [inc] "r" (256UL)
: "memory");
XMMS_RESTORE;
}
static void
xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3)
{
unsigned int lines = bytes >> 8;
xmm_store_t xmm_save[4];
unsigned long cr0;
XMMS_SAVE;
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
PF1(i) \
PF1(i+2) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
PF2(i) \
PF2(i+2) \
PF0(i+4) \
PF0(i+6) \
XO1(i,0) \
XO1(i+1,1) \
XO1(i+2,2) \
XO1(i+3,3) \
XO2(i,0) \
XO2(i+1,1) \
XO2(i+2,2) \
XO2(i+3,3) \
ST(i,0) \
ST(i+1,1) \
ST(i+2,2) \
ST(i+3,3) \
PF0(0)
PF0(2)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addq %[inc], %[p1] ;\n"
" addq %[inc], %[p2] ;\n"
" addq %[inc], %[p3] ;\n"
" decl %[cnt] ; jnz 1b"
: [cnt] "+r" (lines),
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
: [inc] "r" (256UL)
: "memory");
XMMS_RESTORE;
}
static void
xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4)
{
unsigned int lines = bytes >> 8;
xmm_store_t xmm_save[4];
unsigned long cr0;
XMMS_SAVE;
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
PF1(i) \
PF1(i+2) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
PF2(i) \
PF2(i+2) \
XO1(i,0) \
XO1(i+1,1) \
XO1(i+2,2) \
XO1(i+3,3) \
PF3(i) \
PF3(i+2) \
PF0(i+4) \
PF0(i+6) \
XO2(i,0) \
XO2(i+1,1) \
XO2(i+2,2) \
XO2(i+3,3) \
XO3(i,0) \
XO3(i+1,1) \
XO3(i+2,2) \
XO3(i+3,3) \
ST(i,0) \
ST(i+1,1) \
ST(i+2,2) \
ST(i+3,3) \
PF0(0)
PF0(2)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addq %[inc], %[p1] ;\n"
" addq %[inc], %[p2] ;\n"
" addq %[inc], %[p3] ;\n"
" addq %[inc], %[p4] ;\n"
" decl %[cnt] ; jnz 1b"
: [cnt] "+c" (lines),
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
: [inc] "r" (256UL)
: "memory" );
XMMS_RESTORE;
}
static void
xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4, unsigned long *p5)
{
unsigned int lines = bytes >> 8;
xmm_store_t xmm_save[4];
unsigned long cr0;
XMMS_SAVE;
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
PF1(i) \
PF1(i+2) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
PF2(i) \
PF2(i+2) \
XO1(i,0) \
XO1(i+1,1) \
XO1(i+2,2) \
XO1(i+3,3) \
PF3(i) \
PF3(i+2) \
XO2(i,0) \
XO2(i+1,1) \
XO2(i+2,2) \
XO2(i+3,3) \
PF4(i) \
PF4(i+2) \
PF0(i+4) \
PF0(i+6) \
XO3(i,0) \
XO3(i+1,1) \
XO3(i+2,2) \
XO3(i+3,3) \
XO4(i,0) \
XO4(i+1,1) \
XO4(i+2,2) \
XO4(i+3,3) \
ST(i,0) \
ST(i+1,1) \
ST(i+2,2) \
ST(i+3,3) \
PF0(0)
PF0(2)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addq %[inc], %[p1] ;\n"
" addq %[inc], %[p2] ;\n"
" addq %[inc], %[p3] ;\n"
" addq %[inc], %[p4] ;\n"
" addq %[inc], %[p5] ;\n"
" decl %[cnt] ; jnz 1b"
: [cnt] "+c" (lines),
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4),
[p5] "+r" (p5)
: [inc] "r" (256UL)
: "memory");
XMMS_RESTORE;
}
static struct xor_block_template xor_block_sse = {
.name = "generic_sse",
.do_2 = xor_sse_2,
.do_3 = xor_sse_3,
.do_4 = xor_sse_4,
.do_5 = xor_sse_5,
};
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_sse); \
} while (0)
/* We force the use of the SSE xor block because it can write around L2.
We may also be able to load into the L1 only depending on how the cpu
deals with a load to a line that is being prefetched. */
#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+66
View File
@@ -0,0 +1,66 @@
diff -urN linux-2.6.10-orig/include/asm-x86_64/hw_irq.h linux-2.6.10/include/asm-x86_64/hw_irq.h
--- linux-2.6.10-orig/include/asm-x86_64/hw_irq.h 2005-01-06 00:34:38.000000000 -0500
+++ linux-2.6.10/include/asm-x86_64/hw_irq.h 2005-02-25 17:45:37.181518088 -0500
@@ -48,6 +48,7 @@
*
* Vectors 0xf0-0xf9 are free (reserved for future Linux use).
*/
+#if 0
#define SPURIOUS_APIC_VECTOR 0xff
#define ERROR_APIC_VECTOR 0xfe
#define INVALIDATE_TLB_VECTOR 0xfd
@@ -57,7 +58,7 @@
#define KDB_VECTOR 0xf9
#define THERMAL_APIC_VECTOR 0xf0
-
+#endif
/*
* Local APIC timer IRQ vector is on a different priority level,
diff -urN linux-2.6.10-orig/include/asm-x86_64/irq.h linux-2.6.10/include/asm-x86_64/irq.h
--- linux-2.6.10-orig/include/asm-x86_64/irq.h 2005-01-06 00:34:38.000000000 -0500
+++ linux-2.6.10/include/asm-x86_64/irq.h 2005-02-25 17:45:37.181518088 -0500
@@ -10,6 +10,7 @@
* <tomsoft@informatik.tu-chemnitz.de>
*/
+#include "irq_vectors.h"
#define TIMER_IRQ 0
/*
@@ -22,6 +23,7 @@
* the usable vector space is 0x20-0xff (224 vectors)
*/
+#if 0
/*
* The maximum number of vectors supported by x86_64 processors
* is limited to 256. For processors other than x86_64, NR_VECTORS
@@ -38,6 +40,7 @@
#define NR_IRQS 224
#define NR_IRQ_VECTORS 1024
#endif
+#endif
static __inline__ int irq_canonicalize(int irq)
{
diff -urN linux-2.6.10-orig/include/asm-x86_64/posix_types.h linux-2.6.10/include/asm-x86_64/posix_types.h
--- linux-2.6.10-orig/include/asm-x86_64/posix_types.h 2004-10-18 17:55:29.000000000 -0400
+++ linux-2.6.10/include/asm-x86_64/posix_types.h 2005-02-25 17:45:37.183517784 -0500
@@ -6,7 +6,7 @@
* be a little careful about namespace pollution etc. Also, we cannot
* assume GCC is being used.
*/
-
+#ifndef __ASSEMBLY__
typedef unsigned long __kernel_ino_t;
typedef unsigned int __kernel_mode_t;
typedef unsigned long __kernel_nlink_t;
@@ -115,5 +115,5 @@
}
#endif /* defined(__KERNEL__) */
-
+#endif
#endif
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.