bitkeeper revision 1.1085 (40f5624559Jpit7H8wc4PzDqjO-E2g)

Initial checkin of Linux 2.6.
This commit is contained in:
cl349@freefall.cl.cam.ac.uk committed 2004-07-14 16:41:41 +00:00
1 parent 14a97cb239
commit d96977d485
98 files changed
+23776 -2

No files matched your search

+95
View File
@@ -151,6 +151,101 @@
3e5a4e681xMPdF9xCMwpyfuYMySU5g linux-2.4.26-xen-sparse/mm/mremap.c
409ba2e7akOFqQUg6Qyg2s28xcXiMg linux-2.4.26-xen-sparse/mm/page_alloc.c
3e5a4e683HKVU-sxtagrDasRB8eBVw linux-2.4.26-xen-sparse/mm/swapfile.c
40f562372u3A7_kfbYYixPHJJxYUxA linux-2.6.7-xen-sparse/arch/xen/Kconfig
40f56237utH41NPukqHksuNf29IC9A linux-2.6.7-xen-sparse/arch/xen/Kconfig.drivers
40f56237penAAlWVBVDpeQZNFIg8CA linux-2.6.7-xen-sparse/arch/xen/Makefile
40f56237JTc60m1FRlUxkUaGSQKrNw linux-2.6.7-xen-sparse/arch/xen/boot/Makefile
40f56237wubfjJKlfIzZlI3ZM2VgGA linux-2.6.7-xen-sparse/arch/xen/defconfig
40f56237Mta0yHNaMS_qtM2rge0qYA linux-2.6.7-xen-sparse/arch/xen/i386/Kconfig
40f56238u2CJdXNpjsZgHBxeVyY-2g linux-2.6.7-xen-sparse/arch/xen/i386/Makefile
40f56238eczveJ86k_4hNxCLRQIF-g linux-2.6.7-xen-sparse/arch/xen/i386/kernel/Makefile
40f56238rXVTJQKbBuXXLH52qEArcg linux-2.6.7-xen-sparse/arch/xen/i386/kernel/cpu/Makefile
40f562385s4lr6Zg92gExe7UQ4A76Q linux-2.6.7-xen-sparse/arch/xen/i386/kernel/cpu/common.c
40f56238XDtHSijkAFlbv1PT8Bhw_Q linux-2.6.7-xen-sparse/arch/xen/i386/kernel/entry.S
40f56238xFQe9T7M_U_FItM-bZIpLw linux-2.6.7-xen-sparse/arch/xen/i386/kernel/evtchn.c
40f56238bnvciAuyzAiMkdzGErYt1A linux-2.6.7-xen-sparse/arch/xen/i386/kernel/head.S
40f562382aC3_Gt4RG-4ZsfvDRUg3Q linux-2.6.7-xen-sparse/arch/xen/i386/kernel/irq.c
40f56238ue3YRsK52HG7iccNzP1AwQ linux-2.6.7-xen-sparse/arch/xen/i386/kernel/ldt.c
40f56238a8iOVDEoostsbun_sy2i4g linux-2.6.7-xen-sparse/arch/xen/i386/kernel/process.c
40f56238YQIJoYG2ehDGEcdTgLmGbg linux-2.6.7-xen-sparse/arch/xen/i386/kernel/setup.c
40f56238nWMQg7CKbyTy0KJNvCzbtg linux-2.6.7-xen-sparse/arch/xen/i386/kernel/signal.c
40f56238UL9uv78ODDzMwLL9yryeFw linux-2.6.7-xen-sparse/arch/xen/i386/kernel/sysenter.c
40f56238qVGkpO_ycnQA8k03kQzAgA linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c
40f56238NzTgeO63RGoxHrW5NQeO3Q linux-2.6.7-xen-sparse/arch/xen/i386/kernel/timers/Makefile
40f56238BMqG5PuSHufpjbvp_helBw linux-2.6.7-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c
40f562389xNa78YBZciUibQjyRU_Lg linux-2.6.7-xen-sparse/arch/xen/i386/kernel/traps.c
40f56238qASEI_IOhCKWNuwFKNZrKQ linux-2.6.7-xen-sparse/arch/xen/i386/kernel/vmlinux.lds.S
40f56238JypKAUG01ZojFwH7qnZ5uA linux-2.6.7-xen-sparse/arch/xen/i386/kernel/vsyscall.S
40f56238wi6AdNQjm0RT57bSkwb6hg linux-2.6.7-xen-sparse/arch/xen/i386/kernel/vsyscall.lds
40f56238a3w6-byOzexIlMgni76Lcg linux-2.6.7-xen-sparse/arch/xen/i386/mm/Makefile
40f56238ILx8xlbywNbzTdv5Zr4xXQ linux-2.6.7-xen-sparse/arch/xen/i386/mm/fault.c
40f562383SKvDStdtrvzr5fyCbW4rw linux-2.6.7-xen-sparse/arch/xen/i386/mm/hypervisor.c
40f56239xcNylAxuGsQHwi1AyMLV8w linux-2.6.7-xen-sparse/arch/xen/i386/mm/init.c
40f5623906UYHv1rsVUeRc0tFT0dWw linux-2.6.7-xen-sparse/arch/xen/i386/mm/pgtable.c
40f56239zOksGg_H4XD4ye6iZNtoZA linux-2.6.7-xen-sparse/arch/xen/kernel/Makefile
40f56239bvOjuuuViZ0XMlNiREFC0A linux-2.6.7-xen-sparse/arch/xen/kernel/ctrl_if.c
40f56239pYRq5yshPTkv3ujXKc8K6g linux-2.6.7-xen-sparse/arch/xen/kernel/empty.c
40f56239sFcjHiIRmnObRIDF-zaeKQ linux-2.6.7-xen-sparse/arch/xen/kernel/process.c
40f562392LBhwmOxVPsYdkYXMxI_ZQ linux-2.6.7-xen-sparse/arch/xen/kernel/reboot.c
40f56239Dp_vMTgz8TEbvo1hjHGc3w linux-2.6.7-xen-sparse/drivers/xen/Makefile
40f56239Sfle6wGv5FS0wjS_HI150A linux-2.6.7-xen-sparse/drivers/xen/block/Kconfig
40f562395atl9x4suKGhPkjqLOXESg linux-2.6.7-xen-sparse/drivers/xen/block/Makefile
40f56239-JNIaTzlviVJohVdoYOUpw linux-2.6.7-xen-sparse/drivers/xen/block/block.c
40f56239y9naBTXe40Pi2J_z3p-d1g linux-2.6.7-xen-sparse/drivers/xen/block/block.h
40f56239BVfPsXBiWQitXgDRtOsiqg linux-2.6.7-xen-sparse/drivers/xen/block/vbd.c
40f56239fsLjvtD8YBRAWphps4FDjg linux-2.6.7-xen-sparse/drivers/xen/console/Makefile
40f56239afE58Oot-9omHGqq4UJ--A linux-2.6.7-xen-sparse/drivers/xen/console/console.c
40f56239KYxO0YabhPzCTeUuln-lnA linux-2.6.7-xen-sparse/drivers/xen/evtchn/Makefile
40f56239DoibTX6R-ZYd3QTXAB8_TA linux-2.6.7-xen-sparse/drivers/xen/evtchn/evtchn.c
40f56239lrg_Ob0BJ8WBFS1zeg2CYw linux-2.6.7-xen-sparse/drivers/xen/net/Kconfig
40f56239Wd4k_ycG_mFsSO1r5xKdtQ linux-2.6.7-xen-sparse/drivers/xen/net/Makefile
40f56239vUsbJCS9tGFfRVi1YZlGEg linux-2.6.7-xen-sparse/drivers/xen/net/network.c
40f56239YAjS52QG2FIAQpHDZAdGHg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/desc.h
40f5623anSzpuEHgiNmQ56fIRfCoaQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/e820.h
40f5623akIoBsQ3KxSB2kufkbgONXQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/fixmap.h
40f5623aGPlsm0u1LTO-NVZ6AGzNRQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/hypervisor.h
40f5623aJVXQwpJMOLE99XgvGsfQ8Q linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/io.h
40f5623am9BzluYFuV6EQfTd-so3dA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/do_timer.h
40f5623adZQ1IZGPxbDXONjyZGYuTA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/io_ports.h
40f5623aKXkBBxgpLx2NcvkncQ1Yyw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
40f5623aMQZoYuf4ml9v69N3gu8ing linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_mpspec.h
40f5623a8LroVMnZ5YRzJJmIc-zHlw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_reboot.h
40f5623an3wOvFKmpIvqSxQfWzklVQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_resources.h
40f5623ayR1vnzfF__htza35a8Ft-g linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_time.h
40f5623a4YdRdVzYWJzOOoqe8mnrXA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_timer.h
40f5623aDLxmbOtUHvkWztKjAO4EjA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_traps.h
40f5623aDMCsWOFO0jktZ4e8sjwvEg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_post.h
40f5623arsFXkGdPvIqvFi3yFXGR0Q linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_pre.h
40f5623aFTyFTR-vdiA-KaGxk5JOKQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/msr.h
40f5623adgjZq9nAgCt0IXdWl7udSA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/page.h
40f5623a54NuG-7qHihGYmw4wWQnMA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/param.h
40f5623atCokYc2uCysSJ8jFO8TEsw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/pgalloc.h
40f5623aEToIXouJgO-ao5d5pcEt1w linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
40f5623aCCXRPlGpNthVXstGz9ZV3A linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/pgtable.h
40f5623aPCkQQfPtJSooGdhcatrvnQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/processor.h
40f5623bvhcUmESJrtcII6Bmd61b3w linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/ptrace.h
40f5623bzLvxr7WoJIxVf2OH4rCBJg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/segment.h
40f5623bG_LzgG6-qwk292nTc5Wabw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/setup.h
40f5623bgzm_9vwxpzJswlAxg298Gg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h
40f5623bVdKP7Dt7qm8twu3NcnGNbA linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/system.h
40f5623bSgGrvrGRpD71K-lIYqaGgg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/timer.h
40f5623bc8LKPRO09wY5dGDnY_YCpw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/tlbflush.h
40f5623bxUbeGjkRrjDguCy_Gm8RLw linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/xor.h
40f5623bqoi4GEoBiiUc6TZk1HjsMg linux-2.6.7-xen-sparse/include/asm-xen/blkif.h
40f5623bYNP7tHE2zX6YQxp9Zq2utQ linux-2.6.7-xen-sparse/include/asm-xen/ctrl_if.h
40f5623bDU2mp4xcHrO0ThodQ9Vs7w linux-2.6.7-xen-sparse/include/asm-xen/domain_controller.h
40f5623b3Eqs8pAc5WpPX8_jTzV2qw linux-2.6.7-xen-sparse/include/asm-xen/evtchn.h
40f5623bSHoOzh_pYP9ovjpUz019Aw linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/arch-x86_32.h
40f5623c1uIAB_OVr5AFdoOac7zxHA linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/arch-x86_64.h
40f5623cEbvTM2QIJ8G6kJoYMLvFpw linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/dom0_ops.h
40f5623cBiv7JBB2bwezpyMwyDGN_w linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/event_channel.h
40f5623cvr4j1BQI1I82_K5wRocUKg linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/hypervisor-if.h
40f5623cfHK4EBsPz922OqMVkZX6OA linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/physdev.h
40f5623cFINsV23lGJNQNbhO5kus_Q linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/sched_ctl.h
40f5623cb_pJrLt3h_nAzvJsjsV0rQ linux-2.6.7-xen-sparse/include/asm-xen/hypervisor-ifs/trace.h
40f5623cndVUFlkxpf7Lfx7xu8madQ linux-2.6.7-xen-sparse/include/asm-xen/multicall.h
40f5623cTZ80EwjWUBlh44A9F9i_Lg linux-2.6.7-xen-sparse/include/asm-xen/netif.h
40f5623cBiQhPHILVLrl3xa6bDBaRg linux-2.6.7-xen-sparse/include/asm-xen/xen.h
40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Make.defs
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile
+2 -2
View File
@@ -13,8 +13,8 @@ TAGS
extras/mini-os/h/hypervisor-ifs
install
install/*
linux-*-xen*/*
linux-2.4.26-xen/*
linux-*-xen0/*
linux-*-xenU/*
linux-xen-sparse
patches/*
tools/*/build/lib*/*.py
+1
View File
@@ -9,6 +9,7 @@ bd240@labyrinth.cl.cam.ac.uk
br260@br260.wolfson.cam.ac.uk
br260@labyrinth.cl.cam.ac.uk
br260@laudney.cl.cam.ac.uk
cl349@freefall.cl.cam.ac.uk
djm@kirby.fc.hp.com
gm281@boulderdash.cl.cam.ac.uk
iap10@freefall.cl.cam.ac.uk
+67
View File
@@ -0,0 +1,67 @@
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
mainmenu "Linux Kernel Configuration"
config XEN
bool
default y
help
This is the Linux Xen port.
config ARCH_XEN
bool
default y
source "init/Kconfig"
#config VT
# bool
# default y
#config VT_CONSOLE
# bool
# default y
#config HW_CONSOLE
# bool
# default y
choice
prompt "Processor Type"
default X86
config X86
bool "X86"
help
Choose this option if your computer is a X86 architecture.
config X86_64
bool "X86_64"
help
Choose this option if your computer is a X86 architecture.
endchoice
if X86
source "arch/xen/i386/Kconfig"
endif
menu "Executable file formats"
source "fs/Kconfig.binfmt"
endmenu
source "arch/xen/Kconfig.drivers"
source "fs/Kconfig"
source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
@@ -0,0 +1,71 @@
# arch/xen/Kconfig.drivers
menu "Device Drivers"
source "drivers/base/Kconfig"
#source "drivers/block/Kconfig"
source "net/Kconfig"
#source "drivers/input/Kconfig"
config INPUT
tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED
default y
---help---
Say Y here if you have any input device (mouse, keyboard, tablet,
joystick, steering wheel ...) connected to your system and want
it to be available to applications. This includes standard PS/2
keyboard and mouse.
Say N here if you have a headless (no monitor, no keyboard) system.
More information is available: <file:Documentation/input/input.txt>
If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called input.
#source "drivers/char/Kconfig"
config UNIX98_PTYS
bool "Unix98 PTY support" if EMBEDDED
default y
---help---
A pseudo terminal (PTY) is a software device consisting of two
halves: a master and a slave. The slave device behaves identical to
a physical terminal; the master device is used by a process to
read data from and write data to the slave, thereby emulating a
terminal. Typical programs for the master side are telnet servers
and xterms.
Linux has traditionally used the BSD-like names /dev/ptyxx for
masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
has a number of problems. The GNU C library glibc 2.1 and later,
however, supports the Unix98 naming standard: in order to acquire a
pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
terminal is then made available to the process and the pseudo
terminal slave can be accessed as /dev/pts/<number>. What was
traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
All modern Linux systems use the Unix98 ptys. Say Y unless
you're on an embedded system and want to conserve memory.
#source "drivers/video/Kconfig"
#config XEN_EVTCHN
# bool "Xen Event Channel"
# depends on XEN
# default Y
#
#config XEN_CONSOLE
# bool "Xen Console"
# depends on XEN && XEN_EVTCHN
# default Y
# help
# Say Y to build a console driver for Xen.
endmenu
+65
View File
@@ -0,0 +1,65 @@
#
# xen/Makefile
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" cleaning up for this architecture.
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 2004 by Christian Limpach
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
# pick up headers from include/asm-xen/asm in preference over include/asm
NOSTDINC_FLAGS = -nostdinc -iwithprefix include/asm-xen -Iinclude/asm-xen -iwithprefix include
# make uname return the processor arch
UTS_MACHINE := $(XENARCH)
core-y += arch/xen/kernel/
drivers-y += drivers/xen/
include/.asm-ignore:
@rm -f include/.asm-ignore
@mv include/asm include/.asm-ignore
@echo ' SYMLINK include/asm -> include/asm-$(XENARCH)'
$(Q)if [ ! -d include ]; then mkdir -p include; fi;
@ln -fsn asm-$(XENARCH) include/asm
include/asm-xen/asm:
@echo ' SYMLINK $@ -> include/asm-xen/asm-$(XENARCH)'
@ln -fsn asm-$(XENARCH) $@
include/asm-xen/asm-$(XENARCH)/hypervisor-ifs:
@echo ' SYMLINK $@ -> include/asm-xen/hypervisor-ifs'
@ln -fsn ../hypervisor-ifs $@
arch/xen/arch:
@rm -f $@
@ln -fsn $(XENARCH) $@
prepare: include/.asm-ignore include/asm-xen/asm \
include/asm-xen/asm-$(XENARCH)/hypervisor-ifs \
arch/xen/arch ;
all: vmlinuz
vmlinuz: vmlinux
$(Q)$(MAKE) $(build)=arch/xen/boot vmlinuz
archclean:
@if [ -e arch/xen/arch ]; then $(MAKE) $(clean)=arch/xen/arch; fi;
@rm -f arch/xen/arch include/.asm-ignore include/asm-xen/asm
define archhelp
echo '* vmlinuz - Compressed kernel image'
endef
ifneq ($(XENARCH),)
include $(srctree)/arch/xen/$(XENARCH)/Makefile
endif
@@ -0,0 +1,3 @@
vmlinuz: vmlinux FORCE
$(call if_changed,gzip)
+373
View File
@@ -0,0 +1,373 @@
#
# Automatically generated make config: don't edit
#
CONFIG_XEN=y
CONFIG_ARCH_XEN=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_STANDALONE=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
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 is not set
# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
#
# CONFIG_MODULES is not set
CONFIG_X86=y
# CONFIG_X86_64 is not set
#
# X86 Processor Configuration
#
CONFIG_XENARCH="i386"
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_GENERIC_ISA_DMA=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_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_HIGHMEM64G 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_X86_BIOS_REBOOT=y
CONFIG_X86_STD_RESOURCES=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
#
#
# 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_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
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED 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_INPUT=y
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 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_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# 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 is not set
CONFIG_TMPFS=y
# 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_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_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_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
CONFIG_CRC32=y
CONFIG_LIBCRC32C=y
@@ -0,0 +1,784 @@
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
menu "X86 Processor Configuration"
config XENARCH
string
default i386
config MMU
bool
default y
config SBUS
bool
config UID16
bool
default y
config GENERIC_ISA_DMA
bool
default y
choice
prompt "Processor family"
default M686
config M386
bool "386"
---help---
This is the processor type of your CPU. This information is used for
optimizing purposes. In order to compile a kernel that can run on
all x86 CPU types (albeit not optimally fast), you can specify
"386" here.
The kernel will not necessarily run on earlier architectures than
the one you have chosen, e.g. a Pentium optimized kernel will run on
a PPro, but not necessarily on a i486.
Here are the settings recommended for greatest speed:
- "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels
will run on a 386 class machine.
- "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
- "586" for generic Pentium CPUs lacking the TSC
(time stamp counter) register.
- "Pentium-Classic" for the Intel Pentium.
- "Pentium-MMX" for the Intel Pentium MMX.
- "Pentium-Pro" for the Intel Pentium Pro.
- "Pentium-II" for the Intel Pentium II or pre-Coppermine Celeron.
- "Pentium-III" for the Intel Pentium III or Coppermine Celeron.
- "Pentium-4" for the Intel Pentium 4 or P4-based Celeron.
- "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
- "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
- "Crusoe" for the Transmeta Crusoe series.
- "Winchip-C6" for original IDT Winchip.
- "Winchip-2" for IDT Winchip 2.
- "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
- "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
- "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above).
If you don't know what to do, choose "386".
config M486
bool "486"
help
Select this for a 486 series processor, either Intel or one of the
compatible processors from AMD, Cyrix, IBM, or Intel. Includes DX,
DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or
U5S.
config M586
bool "586/K5/5x86/6x86/6x86MX"
help
Select this for an 586 or 686 series processor such as the AMD K5,
the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not
assume the RDTSC (Read Time Stamp Counter) instruction.
config M586TSC
bool "Pentium-Classic"
help
Select this for a Pentium Classic processor with the RDTSC (Read
Time Stamp Counter) instruction for benchmarking.
config M586MMX
bool "Pentium-MMX"
help
Select this for a Pentium with the MMX graphics/multimedia
extended instructions.
config M686
bool "Pentium-Pro"
help
Select this for Intel Pentium Pro chips. This enables the use of
Pentium Pro extended instructions, and disables the init-time guard
against the f00f bug found in earlier Pentiums.
config MPENTIUMII
bool "Pentium-II/Celeron(pre-Coppermine)"
help
Select this for Intel chips based on the Pentium-II and
pre-Coppermine Celeron core. This option enables an unaligned
copy optimization, compiles the kernel with optimization flags
tailored for the chip, and applies any applicable Pentium Pro
optimizations.
config MPENTIUMIII
bool "Pentium-III/Celeron(Coppermine)/Pentium-III Xeon"
help
Select this for Intel chips based on the Pentium-III and
Celeron-Coppermine core. This option enables use of some
extended prefetch instructions in addition to the Pentium II
extensions.
config MPENTIUMM
bool "Pentium M"
help
Select this for Intel Pentium M (not Pentium-4 M)
notebook chips.
config MPENTIUM4
bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon"
help
Select this for Intel Pentium 4 chips. This includes the
Pentium 4, P4-based Celeron and Xeon, and Pentium-4 M
(not Pentium M) chips. This option enables compile flags
optimized for the chip, uses the correct cache shift, and
applies any applicable Pentium III optimizations.
config MK6
bool "K6/K6-II/K6-III"
help
Select this for an AMD K6-family processor. Enables use of
some extended instructions, and passes appropriate optimization
flags to GCC.
config MK7
bool "Athlon/Duron/K7"
help
Select this for an AMD Athlon K7-family processor. Enables use of
some extended instructions, and passes appropriate optimization
flags to GCC.
config MK8
bool "Opteron/Athlon64/Hammer/K8"
help
Select this for an AMD Opteron or Athlon64 Hammer-family processor. Enables
use of some extended instructions, and passes appropriate optimization
flags to GCC.
config MCRUSOE
bool "Crusoe"
help
Select this for a Transmeta Crusoe processor. Treats the processor
like a 586 with TSC, and sets some GCC optimization flags (like a
Pentium Pro with no alignment requirements).
config MWINCHIPC6
bool "Winchip-C6"
help
Select this for an IDT Winchip C6 chip. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment requirements.
config MWINCHIP2
bool "Winchip-2"
help
Select this for an IDT Winchip-2. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment requirements.
config MWINCHIP3D
bool "Winchip-2A/Winchip-3"
help
Select this for an IDT Winchip-2A or 3. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment reqirements. Also enable out of order memory
stores for this CPU, which can increase performance of some
operations.
config MCYRIXIII
bool "CyrixIII/VIA-C3"
help
Select this for a Cyrix III or C3 chip. Presently Linux and GCC
treat this chip as a generic 586. Whilst the CPU is 686 class,
it lacks the cmov extension which gcc assumes is present when
generating 686 code.
Note that Nehemiah (Model 9) and above will not boot with this
kernel due to them lacking the 3DNow! instructions used in earlier
incarnations of the CPU.
config MVIAC3_2
bool "VIA C3-2 (Nehemiah)"
help
Select this for a VIA C3 "Nehemiah". Selecting this enables usage
of SSE and tells gcc to treat the CPU as a 686.
Note, this kernel will not boot on older (pre model 9) C3s.
endchoice
config X86_GENERIC
bool "Generic x86 support"
help
Instead of just including optimizations for the selected
x86 variant (e.g. PII, Crusoe or Athlon), include some more
generic optimizations as well. This will make the kernel
perform better on x86 CPUs other than that selected.
This is really intended for distributors who need more
generic optimizations.
#
# Define implied options from the CPU selection here
#
config X86_CMPXCHG
bool
depends on !M386
default y
config X86_XADD
bool
depends on !M386
default y
config X86_L1_CACHE_SHIFT
int
default "7" if MPENTIUM4 || X86_GENERIC
default "4" if X86_ELAN || M486 || M386
default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2
default "6" if MK7 || MK8 || MPENTIUMM
config RWSEM_GENERIC_SPINLOCK
bool
depends on M386
default y
config RWSEM_XCHGADD_ALGORITHM
bool
depends on !M386
default y
config X86_PPRO_FENCE
bool
depends on M686 || M586MMX || M586TSC || M586 || M486 || M386
default y
config X86_F00F_BUG
bool
depends on M586MMX || M586TSC || M586 || M486 || M386
default y
config X86_WP_WORKS_OK
bool
depends on !M386
default y
config X86_INVLPG
bool
depends on !M386
default y
config X86_BSWAP
bool
depends on !M386
default y
config X86_POPAD_OK
bool
depends on !M386
default y
config X86_ALIGNMENT_16
bool
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2
default y
config X86_GOOD_APIC
bool
depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8
default y
config X86_INTEL_USERCOPY
bool
depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7
default y
config X86_USE_PPRO_CHECKSUM
bool
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2
default y
config X86_USE_3DNOW
bool
depends on MCYRIXIII || MK7
default y
config X86_OOSTORE
bool
depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
default y
config HPET_TIMER
bool "HPET Timer Support"
help
This enables the use of the HPET for the kernel's internal timer.
HPET is the next generation timer replacing legacy 8254s.
You can safely choose Y here. However, HPET will only be
activated if the platform and the BIOS support this feature.
Otherwise the 8254 will be used for timing services.
Choose N to continue using the legacy 8254 timer.
config HPET_EMULATE_RTC
def_bool HPET_TIMER && RTC=y
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.
Note that if you say Y here and choose architecture "586" or
"Pentium" under "Processor family", the kernel will not work on 486
architectures. Similarly, multiprocessor kernels for the "PPro"
architecture may not work on all Pentium based boards.
People using multiprocessor machines who say Y here should also say
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
See also the <file:Documentation/smp.txt>,
<file:Documentation/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
config NR_CPUS
int "Maximum number of CPUs (2-255)"
range 2 255
depends on SMP
default "32" if X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000
default "8"
help
This allows you to specify the maximum number of CPUs which this
kernel will support. The maximum supported value is 255 and the
minimum value which makes sense is 2.
This is purely to save memory - each supported CPU adds
approximately eight kilobytes to the kernel image.
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 PREEMPT
bool "Preemptible Kernel"
help
This option reduces the latency of the kernel when reacting to
real-time or interactive events by allowing a low priority process to
be preempted even if it is in kernel mode executing a system call.
This allows applications to run more reliably even when the system is
under load.
Say Y here if you are building a kernel for a desktop, embedded
or real-time system. Say N if you are unsure.
#config X86_TSC
# bool
# depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ
# default y
#config X86_MCE
# bool "Machine Check Exception"
# depends on !X86_VOYAGER
# ---help---
# Machine Check Exception support allows the processor to notify the
# kernel if it detects a problem (e.g. overheating, component failure).
# The action the kernel takes depends on the severity of the problem,
# ranging from a warning message on the console, to halting the machine.
# Your processor must be a Pentium or newer to support this - check the
# flags in /proc/cpuinfo for mce. Note that some older Pentium systems
# have a design flaw which leads to false MCE events - hence MCE is
# disabled on all P5 processors, unless explicitly enabled with "mce"
# as a boot argument. Similarly, if MCE is built in and creates a
# problem on some new non-standard machine, you can boot with "nomce"
# to disable it. MCE support simply ignores non-MCE processors like
# the 386 and 486, so nearly everyone can say Y here.
#config X86_MCE_NONFATAL
# tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
# depends on X86_MCE
# help
# Enabling this feature starts a timer that triggers every 5 seconds which
# will look at the machine check registers to see if anything happened.
# Non-fatal problems automatically get corrected (but still logged).
# Disable this if you don't want to see these messages.
# Seeing the messages this option prints out may be indicative of dying hardware,
# or out-of-spec (ie, overclocked) hardware.
# This option only does something on certain CPUs.
# (AMD Athlon/Duron and Intel Pentium 4)
#config X86_MCE_P4THERMAL
# bool "check for P4 thermal throttling interrupt."
# depends on X86_MCE && (X86_UP_APIC || SMP)
# help
# Enabling this feature will cause a message to be printed when the P4
# enters thermal throttling.
#config MICROCODE
# tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
# ---help---
# If you say Y here and also to "/dev file system support" in the
# 'File systems' section, you will be able to update the microcode on
# Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
# Pentium III, Pentium 4, Xeon etc. 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.
#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.
source "drivers/firmware/Kconfig"
choice
prompt "High Memory Support"
default NOHIGHMEM
config NOHIGHMEM
bool "off"
---help---
Linux can use up to 64 Gigabytes of physical memory on x86 systems.
However, the address space of 32-bit x86 processors is only 4
Gigabytes large. That means that, if you have a large amount of
physical memory, not all of it can be "permanently mapped" by the
kernel. The physical memory that's not permanently mapped is called
"high memory".
If you are compiling a kernel which will never run on a machine with
more than 1 Gigabyte total physical RAM, answer "off" here (default
choice and suitable for most users). This will result in a "3GB/1GB"
split: 3GB are mapped so that each process sees a 3GB virtual memory
space and the remaining part of the 4GB virtual memory space is used
by the kernel to permanently map as much physical memory as
possible.
If the machine has between 1 and 4 Gigabytes physical RAM, then
answer "4GB" here.
If more than 4 Gigabytes is used then answer "64GB" here. This
selection turns Intel PAE (Physical Address Extension) mode on.
PAE implements 3-level paging on IA32 processors. PAE is fully
supported by Linux, PAE mode is implemented on all recent Intel
processors (Pentium Pro and better). NOTE: If you say "64GB" here,
then the kernel will not boot on CPUs that don't support PAE!
The actual amount of total physical memory will either be
auto detected or can be forced by using a kernel command line option
such as "mem=256M". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
If unsure, say "off".
config HIGHMEM4G
bool "4GB"
help
Select this if you have a 32-bit processor and between 1 and 4
gigabytes of physical RAM.
config HIGHMEM64G
bool "64GB"
help
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
endchoice
config HIGHMEM
bool
depends on HIGHMEM64G || HIGHMEM4G
default y
config X86_PAE
bool
depends on HIGHMEM64G
default y
# Common NUMA Features
config NUMA
bool "Numa Memory Allocation and Scheduler Support"
depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
default n if X86_PC
default y if (X86_NUMAQ || X86_SUMMIT)
# Need comments to help the hapless user trying to turn on NUMA support
comment "NUMA (NUMA-Q) requires SMP, 64GB highmem support"
depends on X86_NUMAQ && (!HIGHMEM64G || !SMP)
comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
depends on X86_SUMMIT && (!HIGHMEM64G || !ACPI)
config DISCONTIGMEM
bool
depends on NUMA
default y
config HAVE_ARCH_BOOTMEM_NODE
bool
depends on NUMA
default y
config HIGHPTE
bool "Allocate 3rd-level pagetables from highmem"
depends on HIGHMEM4G || HIGHMEM64G
help
The VM uses one page table entry for each page of physical memory.
For systems with a lot of RAM, this can be wasteful of precious
low memory. Setting this option will put user-space page table
entries in high memory.
#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:
#
# The Cyrix 6x86, 6x86MX and M II processors have Address Range
# Registers (ARRs) which provide a similar functionality to MTRRs. For
# these, the ARRs are used to emulate the MTRRs.
# The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
# MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing
# write-combining. All of these processors are supported by this code
# and it makes sense to say Y here if you have one of them.
#
# 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.
#
# You can safely say Y even if your machine doesn't have MTRRs, you'll
# just add about 9 KB to your kernel.
#
# See <file:Documentation/mtrr.txt> for more information.
config IRQBALANCE
bool "Enable kernel irq balancing"
depends on SMP && X86_IO_APIC
default y
help
The default yes will allow the kernel to do irq load balancing.
Saying no will keep the kernel from doing irq load balancing.
config HAVE_DEC_LOCK
bool
depends on (SMP || PREEMPT) && X86_CMPXCHG
default y
# turning this on wastes a bunch of space.
# Summit needs it only when NUMA is on
config BOOT_IOREMAP
bool
depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
default y
config REGPARM
bool "Use register arguments (EXPERIMENTAL)"
depends on EXPERIMENTAL
default n
help
Compile the kernel with -mregparm=3. This uses an different ABI
and passes the first three arguments of a function call in registers.
This will probably break binary only modules.
This feature is only enabled for gcc-3.0 and later - earlier compilers
generate incorrect output with certain kernel constructs when
-mregparm=3 is used.
menu "Kernel hacking"
config DEBUG_KERNEL
bool "Kernel debugging"
help
Say Y here if you are developing drivers or trying to debug and
identify kernel problems.
config EARLY_PRINTK
bool "Early printk" if EMBEDDED
default y
help
Write kernel log output directly into the VGA buffer or to a serial
port.
This is useful for kernel debugging when your machine crashes very
early before the console code is initialized. For normal operation
it is not recommended because it looks ugly and doesn't cooperate
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
depends on DEBUG_KERNEL
config DEBUG_STACK_USAGE
bool "Stack utilization instrumentation"
depends on DEBUG_KERNEL
help
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T and sysrq-P debug output.
This option will slow down process creation somewhat.
config DEBUG_SLAB
bool "Debug memory allocations"
depends on DEBUG_KERNEL
help
Say Y here to have the kernel do limited verification on memory
allocation as well as poisoning memory on free to catch use of freed
memory.
config MAGIC_SYSRQ
bool "Magic SysRq key"
depends on DEBUG_KERNEL
help
If you say Y here, you will have some control over the system even
if the system crashes for example during kernel debugging (e.g., you
will be able to flush the buffer cache to disk, reboot the system
immediately or dump some status information). This is accomplished
by pressing various keys while holding SysRq (Alt+PrintScreen). It
also works on a serial console (on PC hardware at least), if you
send a BREAK and then within 5 seconds a command keypress. The
keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
unless you really know what this hack does.
config DEBUG_SPINLOCK
bool "Spinlock debugging"
depends on DEBUG_KERNEL
help
Say Y here and build SMP to catch missing spinlock initialization
and certain other kinds of spinlock errors commonly made. This is
best used in conjunction with the NMI watchdog so that spinlock
deadlocks are also debuggable.
config DEBUG_PAGEALLOC
bool "Page alloc debugging"
depends on DEBUG_KERNEL
help
Unmap pages from the kernel linear mapping after free_pages().
This results in a large slowdown, but helps to find certain types
of memory corruptions.
config DEBUG_HIGHMEM
bool "Highmem debugging"
depends on DEBUG_KERNEL && HIGHMEM
help
This options enables addition error checking for high memory systems.
Disable for production systems.
config DEBUG_INFO
bool "Compile the kernel with debug info"
depends on DEBUG_KERNEL
help
If you say Y here the resulting kernel image will include
debugging info resulting in a larger kernel image.
Say Y here only if you plan to use gdb to debug the kernel.
If you don't debug the kernel, you can say N.
config DEBUG_SPINLOCK_SLEEP
bool "Sleep-inside-spinlock checking"
help
If you say Y here, various routines which may sleep will become very
noisy if they are called with a spinlock held.
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
help
If you say Y here the resulting kernel image will be slightly larger
and slower, but it will give very useful debugging information.
If you don't debug the kernel, you can say N, but we may not be able
to solve problems without frame pointers.
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
help
If you say Y here the kernel will use a 4Kb stacksize for the
kernel stack attached to each process/thread. This facilitates
running more threads on a system and also reduces the pressure
on the VM subsystem for higher order allocations. This option
will also use IRQ stacks to compensate for the reduced stackspace.
config X86_FIND_SMP_CONFIG
bool
depends on X86_LOCAL_APIC || X86_VOYAGER
default y
config X86_MPPARSE
bool
depends on X86_LOCAL_APIC && !X86_VISWS
default y
endmenu
config X86_SMP
bool
depends on SMP && !X86_VOYAGER
default y
config X86_HT
bool
depends on SMP && !(X86_VISWS || X86_VOYAGER)
default y
config X86_BIOS_REBOOT
bool
depends on !(X86_VISWS || X86_VOYAGER)
default y
config X86_TRAMPOLINE
bool
depends on X86_SMP || (X86_VOYAGER && SMP)
default y
# std_resources is overridden for pc9800, but that's not
# a currently selectable arch choice
config X86_STD_RESOURCES
bool
default y
config PC
bool
depends on X86 && !EMBEDDED
default y
endmenu
@@ -0,0 +1,97 @@
#
# i386/Makefile
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" cleaning up for this architecture.
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 1994 by Linus Torvalds
#
# 19990713 Artur Skawina <skawina@geocities.com>
# Added '-march' and '-mpreferred-stack-boundary' support
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
LDFLAGS := -m elf_i386
LDFLAGS_vmlinux :=
CHECK := $(CHECK) -D__i386__=1
CFLAGS += -pipe -msoft-float
# prevent gcc from keeping the stack 16 byte aligned
CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
align := $(subst -functions=0,,$(call check_gcc,-falign-functions=0,-malign-functions=0))
cflags-$(CONFIG_M386) += -march=i386
cflags-$(CONFIG_M486) += -march=i486
cflags-$(CONFIG_M586) += -march=i586
cflags-$(CONFIG_M586TSC) += -march=i586
cflags-$(CONFIG_M586MMX) += $(call check_gcc,-march=pentium-mmx,-march=i586)
cflags-$(CONFIG_M686) += -march=i686
cflags-$(CONFIG_MPENTIUMII) += $(call check_gcc,-march=pentium2,-march=i686)
cflags-$(CONFIG_MPENTIUMIII) += $(call check_gcc,-march=pentium3,-march=i686)
cflags-$(CONFIG_MPENTIUMM) += $(call check_gcc,-march=pentium3,-march=i686)
cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686)
cflags-$(CONFIG_MK6) += -march=k6
# Please note, that patches that add -march=athlon-xp and friends are pointless.
# They make zero difference whatsosever to performance at this time.
cflags-$(CONFIG_MK7) += $(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4)
cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4))
cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MWINCHIPC6) += $(call check_gcc,-march=winchip-c6,-march=i586)
cflags-$(CONFIG_MWINCHIP2) += $(call check_gcc,-march=winchip2,-march=i586)
cflags-$(CONFIG_MWINCHIP3D) += $(call check_gcc,-march=winchip2,-march=i586)
cflags-$(CONFIG_MCYRIXIII) += $(call check_gcc,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MVIAC3_2) += $(call check_gcc,-march=c3-2,-march=i686)
# AMD Elan support
cflags-$(CONFIG_X86_ELAN) += -march=i486
# -mregparm=3 works ok on gcc-3.0 and later
#
GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
# Disable unit-at-a-time mode, it makes gcc use a lot more stack
# due to the lack of sharing of stacklots.
CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
CFLAGS += $(cflags-y)
head-y := arch/xen/i386/kernel/head.o arch/xen/i386/kernel/init_task.o
libs-y += arch/i386/lib/
core-y += arch/xen/i386/kernel/ \
arch/xen/i386/mm/
# \
# arch/xen/$(mcore-y)/
drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/
drivers-$(CONFIG_PCI) += arch/i386/pci/
# must be linked after kernel/
drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/
drivers-$(CONFIG_PM) += arch/i386/power/
# for clean
obj- += kernel/
#obj- += ../../i386/lib/ ../../i386/mm/
#../../i386/$(mcore-y)/
#obj- += ../../i386/pci/ ../../i386/oprofile/ ../../i386/power/
xenflags-y += -Iinclude/asm-xen/asm-i386/mach-xen
CFLAGS += $(xenflags-y)
AFLAGS += $(xenflags-y)
prepare: include/asm-$(XENARCH)/asm_offsets.h
CLEAN_FILES += include/asm-$(XENARCH)/asm_offsets.h
arch/$(XENARCH)/kernel/asm-offsets.s: include/asm include/.asm-ignore \
include/linux/version.h include/config/MARKER
include/asm-$(XENARCH)/asm_offsets.h: arch/$(XENARCH)/kernel/asm-offsets.s
$(call filechk,gen-asm-offsets)
@@ -0,0 +1,94 @@
#
# Makefile for the linux kernel.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
CFLAGS += -Iarch/$(XENARCH)/kernel
extra-y := head.o init_task.o vmlinux.lds.s
obj-y := traps.o irq.o ldt.o setup.o entry.o time.o process.o signal.o
c-obj-y := semaphore.o vm86.o \
ptrace.o ioport.o sys_i386.o \
pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
doublefault.o
s-obj-y :=
#obj-y += hypervisor.o
obj-y += evtchn.o
obj-y += cpu/
obj-y += timers/
c-obj-$(CONFIG_ACPI_BOOT) += acpi/
#c-obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
c-obj-$(CONFIG_MCA) += mca.o
c-obj-$(CONFIG_X86_MSR) += msr.o
c-obj-$(CONFIG_X86_CPUID) += cpuid.o
c-obj-$(CONFIG_MICROCODE) += microcode.o
c-obj-$(CONFIG_APM) += apm.o
c-obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
c-obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
c-obj-$(CONFIG_X86_MPPARSE) += mpparse.o
c-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
c-obj-$(CONFIG_X86_IO_APIC) += io_apic.o
c-obj-$(CONFIG_X86_NUMAQ) += numaq.o
c-obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o
c-obj-$(CONFIG_MODULES) += module.o
obj-y += sysenter.o
obj-y += vsyscall.o
c-obj-$(CONFIG_ACPI_SRAT) += srat.o
c-obj-$(CONFIG_HPET_TIMER) += time_hpet.o
c-obj-$(CONFIG_EFI) += efi.o efi_stub.o
c-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
c-obj-$(CONFIG_X86_STD_RESOURCES) += std_resources.o
EXTRA_AFLAGS := -traditional
c-obj-$(CONFIG_SCx200) += scx200.o
AFLAGS_vmlinux.lds.o += -U$(XENARCH)
# vsyscall.o contains the vsyscall DSO images as __initdata.
# We must build both images before we can assemble it.
# Note: kbuild does not track this dependency due to usage of .incbin
$(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so
targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so)
# The DSO images are built using a special linker script.
quiet_cmd_syscall = SYSCALL $@
cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@
vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1
SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags)
$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
$(obj)/vsyscall-%.so: $(obj)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
$(call if_changed,syscall)
# We also create a special relocatable object that should mirror the symbol
# table and layout of the linked DSO. With ld -R we can then refer to
# these symbols in the kernel code rather than hand-coded addresses.
extra-y += vsyscall-syms.o
$(obj)/built-in.o: $(obj)/vsyscall-syms.o
$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
SYSCFLAGS_vsyscall-syms.o = -r
$(obj)/vsyscall-syms.o: $(obj)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE
$(call if_changed,syscall)
c-link := init_task.o
s-link := vsyscall-int80.o vsyscall-sysenter.o vsyscall-sigreturn.o
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)) $(patsubst %.o,$(obj)/%.S,$(s-obj-y) $(s-link)):
@ln -fsn $(srctree)/arch/i386/kernel/$(notdir $@) $@
$(obj)/vsyscall-int80.S: $(obj)/vsyscall-sigreturn.S
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,31 @@
#
# Makefile for x86-compatible CPU details and quirks
#
CFLAGS += -Iarch/i386/kernel/cpu
obj-y := common.o
c-obj-y += proc.o
c-obj-y += amd.o
c-obj-y += cyrix.o
c-obj-y += centaur.o
c-obj-y += transmeta.o
c-obj-y += intel.o
c-obj-y += rise.o
c-obj-y += nexgen.o
c-obj-y += umc.o
#obj-$(CONFIG_X86_MCE) += ../../../../i386/kernel/cpu/mcheck/
#obj-$(CONFIG_MTRR) += ../../../../i386/kernel/cpu/mtrr/
#obj-$(CONFIG_CPU_FREQ) += ../../../../i386/kernel/cpu/cpufreq/
c-link :=
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/i386/kernel/cpu/$(notdir $@) $@
obj-y += $(c-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
@@ -0,0 +1,597 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/smp.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/msr.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/hypervisor.h>
#include "cpu.h"
static int cachesize_override __initdata = -1;
static int disable_x86_fxsr __initdata = 0;
static int disable_x86_serial_nr __initdata = 1;
struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
extern void mcheck_init(struct cpuinfo_x86 *c);
extern int disable_pse;
static void default_init(struct cpuinfo_x86 * c)
{
/* Not much we can do here... */
/* Check if at least it has cpuid */
if (c->cpuid_level == -1) {
/* No cpuid. It must be an ancient CPU */
if (c->x86 == 4)
strcpy(c->x86_model_id, "486");
else if (c->x86 == 3)
strcpy(c->x86_model_id, "386");
}
}
static struct cpu_dev default_cpu = {
.c_init = default_init,
};
static struct cpu_dev * this_cpu = &default_cpu;
static int __init cachesize_setup(char *str)
{
get_option (&str, &cachesize_override);
return 1;
}
__setup("cachesize=", cachesize_setup);
int __init get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
char *p, *q;
if (cpuid_eax(0x80000000) < 0x80000004)
return 0;
v = (unsigned int *) c->x86_model_id;
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
/* Intel chips right-justify this string for some dumb reason;
undo that brain damage */
p = q = &c->x86_model_id[0];
while ( *p == ' ' )
p++;
if ( p != q ) {
while ( *p )
*q++ = *p++;
while ( q <= &c->x86_model_id[48] )
*q++ = '\0'; /* Zero-pad the rest */
}
return 1;
}
void __init display_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int n, dummy, ecx, edx, l2size;
n = cpuid_eax(0x80000000);
if (n >= 0x80000005) {
cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
c->x86_cache_size=(ecx>>24)+(edx>>24);
}
if (n < 0x80000006) /* Some chips just has a large L1. */
return;
ecx = cpuid_ecx(0x80000006);
l2size = ecx >> 16;
/* do processor-specific cache resizing */
if (this_cpu->c_size_cache)
l2size = this_cpu->c_size_cache(c,l2size);
/* Allow user to override all this if necessary. */
if (cachesize_override != -1)
l2size = cachesize_override;
if ( l2size == 0 )
return; /* Again, no L2 cache is possible */
c->x86_cache_size = l2size;
printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
l2size, ecx & 0xFF);
}
/* Naming convention should be: <Name> [(<Codename>)] */
/* This table only is used unless init_<vendor>() below doesn't set it; */
/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
/* Look up CPU names by table lookup. */
static char __init *table_lookup_model(struct cpuinfo_x86 *c)
{
struct cpu_model_info *info;
if ( c->x86_model >= 16 )
return NULL; /* Range check */
if (!this_cpu)
return NULL;
info = this_cpu->c_models;
while (info && info->family) {
if (info->family == c->x86)
return info->model_names[c->x86_model];
info++;
}
return NULL; /* Not found */
}
void __init get_cpu_vendor(struct cpuinfo_x86 *c, int early)
{
char *v = c->x86_vendor_id;
int i;
for (i = 0; i < X86_VENDOR_NUM; i++) {
if (cpu_devs[i]) {
if (!strcmp(v,cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] &&
!strcmp(v,cpu_devs[i]->c_ident[1]))) {
c->x86_vendor = i;
if (!early)
this_cpu = cpu_devs[i];
break;
}
}
}
}
static int __init x86_fxsr_setup(char * s)
{
disable_x86_fxsr = 1;
return 1;
}
__setup("nofxsr", x86_fxsr_setup);
/* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(u32 flag)
{
u32 f1, f2;
asm("pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0,%1\n\t"
"xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1^f2) & flag) != 0;
}
/* Probe for the CPUID instruction */
int __init have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
/* Do minimum CPU detection early.
Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
The others are not touched to avoid unwanted side effects. */
void __init early_cpu_detect(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
c->x86_cache_alignment = 32;
if (!have_cpuid_p())
return;
/* Get vendor name */
cpuid(0x00000000, &c->cpuid_level,
(int *)&c->x86_vendor_id[0],
(int *)&c->x86_vendor_id[8],
(int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c, 1);
c->x86 = 4;
if (c->cpuid_level >= 0x00000001) {
u32 junk, tfms, cap0, misc;
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
if (c->x86 == 0xf) {
c->x86 += (tfms >> 20) & 0xff;
c->x86_model += ((tfms >> 16) & 0xF) << 4;
}
c->x86_mask = tfms & 15;
if (cap0 & (1<<19))
c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
}
early_intel_workaround(c);
}
void __init generic_identify(struct cpuinfo_x86 * c)
{
u32 tfms, xlvl;
int junk;
if (have_cpuid_p()) {
/* Get vendor name */
cpuid(0x00000000, &c->cpuid_level,
(int *)&c->x86_vendor_id[0],
(int *)&c->x86_vendor_id[8],
(int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c, 0);
/* Initialize the standard set of capabilities */
/* Note that the vendor-specific code below might override */
/* Intel-defined flags: level 0x00000001 */
if ( c->cpuid_level >= 0x00000001 ) {
u32 capability, excap;
cpuid(0x00000001, &tfms, &junk, &excap, &capability);
c->x86_capability[0] = capability;
c->x86_capability[4] = excap;
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
if (c->x86 == 0xf) {
c->x86 += (tfms >> 20) & 0xff;
c->x86_model += ((tfms >> 16) & 0xF) << 4;
}
c->x86_mask = tfms & 15;
} else {
/* Have CPUID level 0 only - unheard of */
c->x86 = 4;
}
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
if ( (xlvl & 0xffff0000) == 0x80000000 ) {
if ( xlvl >= 0x80000001 )
c->x86_capability[1] = cpuid_edx(0x80000001);
if ( xlvl >= 0x80000004 )
get_model_name(c); /* Default name */
}
}
}
static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
/* Disable processor serial number */
unsigned long lo,hi;
rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
lo |= 0x200000;
wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
printk(KERN_NOTICE "CPU serial number disabled.\n");
clear_bit(X86_FEATURE_PN, c->x86_capability);
/* Disabling the serial number may affect the cpuid level */
c->cpuid_level = cpuid_eax(0);
}
}
static int __init x86_serial_nr_setup(char *s)
{
disable_x86_serial_nr = 0;
return 1;
}
__setup("serialnumber", x86_serial_nr_setup);
/*
* This does the hard work of actually picking apart the CPU stuff...
*/
void __init identify_cpu(struct cpuinfo_x86 *c)
{
int i;
c->loops_per_jiffy = loops_per_jiffy;
c->x86_cache_size = -1;
c->x86_vendor = X86_VENDOR_UNKNOWN;
c->cpuid_level = -1; /* CPUID not detected */
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (!have_cpuid_p()) {
/* First of all, decide if this is a 486 or higher */
/* It's a 486 if we can modify the AC flag */
if ( flag_is_changeable_p(X86_EFLAGS_AC) )
c->x86 = 4;
else
c->x86 = 3;
}
generic_identify(c);
printk(KERN_DEBUG "CPU: After generic identify, caps: %08lx %08lx %08lx %08lx\n",
c->x86_capability[0],
c->x86_capability[1],
c->x86_capability[2],
c->x86_capability[3]);
if (this_cpu->c_identify) {
this_cpu->c_identify(c);
printk(KERN_DEBUG "CPU: After vendor identify, caps: %08lx %08lx %08lx %08lx\n",
c->x86_capability[0],
c->x86_capability[1],
c->x86_capability[2],
c->x86_capability[3]);
}
/*
* Vendor-specific initialization. In this section we
* canonicalize the feature flags, meaning if there are
* features a certain CPU supports which CPUID doesn't
* tell us, CPUID claiming incorrect flags, or other bugs,
* we handle them here.
*
* At the end of this section, c->x86_capability better
* indicate the features this CPU genuinely supports!
*/
if (this_cpu->c_init)
this_cpu->c_init(c);
/* Disable the PN if appropriate */
squash_the_stupid_serial_number(c);
/*
* The vendor-specific functions might have changed features. Now
* we do "generic changes."
*/
/* TSC disabled? */
if ( tsc_disable )
clear_bit(X86_FEATURE_TSC, c->x86_capability);
/* FXSR disabled? */
if (disable_x86_fxsr) {
clear_bit(X86_FEATURE_FXSR, c->x86_capability);
clear_bit(X86_FEATURE_XMM, c->x86_capability);
}
if (disable_pse)
clear_bit(X86_FEATURE_PSE, c->x86_capability);
/* If the model name is still unset, do table lookup. */
if ( !c->x86_model_id[0] ) {
char *p;
p = table_lookup_model(c);
if ( p )
strcpy(c->x86_model_id, p);
else
/* Last resort... */
sprintf(c->x86_model_id, "%02x/%02x",
c->x86_vendor, c->x86_model);
}
/* Now the feature flags better reflect actual CPU features! */
printk(KERN_DEBUG "CPU: After all inits, caps: %08lx %08lx %08lx %08lx\n",
c->x86_capability[0],
c->x86_capability[1],
c->x86_capability[2],
c->x86_capability[3]);
/*
* On SMP, boot_cpu_data holds the common feature set between
* all CPUs; so make sure that we indicate which features are
* common between the CPUs. The first time this routine gets
* executed, c == &boot_cpu_data.
*/
if ( c != &boot_cpu_data ) {
/* AND the already accumulated flags with these */
for ( i = 0 ; i < NCAPINTS ; i++ )
boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
}
/* Init Machine Check Exception if available. */
#ifdef CONFIG_X86_MCE
mcheck_init(c);
#endif
}
/*
* Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
*/
void __init dodgy_tsc(void)
{
if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
( boot_cpu_data.x86_vendor == X86_VENDOR_NSC ))
cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
}
void __init print_cpu_info(struct cpuinfo_x86 *c)
{
char *vendor = NULL;
if (c->x86_vendor < X86_VENDOR_NUM)
vendor = this_cpu->c_vendor;
else if (c->cpuid_level >= 0)
vendor = c->x86_vendor_id;
if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
printk("%s ", vendor);
if (!c->x86_model_id[0])
printk("%d86", c->x86);
else
printk("%s", c->x86_model_id);
if (c->x86_mask || c->cpuid_level >= 0)
printk(" stepping %02x\n", c->x86_mask);
else
printk("\n");
}
unsigned long cpu_initialized __initdata = 0;
/* This is hacky. :)
* We're emulating future behavior.
* In the future, the cpu-specific init functions will be called implicitly
* via the magic of initcalls.
* They will insert themselves into the cpu_devs structure.
* Then, when cpu_init() is called, we can just iterate over that array.
*/
extern int intel_cpu_init(void);
extern int cyrix_init_cpu(void);
extern int nsc_init_cpu(void);
extern int amd_init_cpu(void);
extern int centaur_init_cpu(void);
extern int transmeta_init_cpu(void);
extern int rise_init_cpu(void);
extern int nexgen_init_cpu(void);
extern int umc_init_cpu(void);
void early_cpu_detect(void);
void __init early_cpu_init(void)
{
early_cpu_detect();
intel_cpu_init();
cyrix_init_cpu();
nsc_init_cpu();
amd_init_cpu();
centaur_init_cpu();
transmeta_init_cpu();
rise_init_cpu();
nexgen_init_cpu();
umc_init_cpu();
#ifdef CONFIG_DEBUG_PAGEALLOC
/* pse is not compatible with on-the-fly unmapping,
* disable it even if the cpus claim to support it.
*/
clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
disable_pse = 1;
#endif
}
void __init cpu_gdt_init(struct Xgt_desc_struct *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;
wrprotect_bootpt(swapper_pg_dir, (void *)va, 1);
}
flush_page_update_queue();
if (HYPERVISOR_set_gdt(frames, gdt_descr->size / 8))
BUG();
lgdt_finish();
}
/*
* cpu_init() initializes state that is per-CPU. Some data is already
* initialized (naturally) in the bootstrap process, such as the GDT
* and IDT. We reload them nevertheless, this function acts as a
* 'CPU state barrier', nothing should get across.
*/
void __init cpu_init (void)
{
int cpu = smp_processor_id();
struct tss_struct * t = init_tss + cpu;
struct thread_struct *thread = &current->thread;
if (test_and_set_bit(cpu, &cpu_initialized)) {
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
for (;;) local_irq_enable();
}
printk(KERN_INFO "Initializing CPU#%d\n", cpu);
if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
if (tsc_disable && cpu_has_tsc) {
printk(KERN_NOTICE "Disabling TSC...\n");
/**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
set_in_cr4(X86_CR4_TSD);
}
/*
* Initialize the per-CPU GDT with the boot GDT,
* and set up the GDT descriptor:
*/
if (cpu) {
cpu_gdt_descr[cpu].size = GDT_SIZE;
cpu_gdt_descr[cpu].address = 0; /* XXXcl alloc page */
BUG(); /* XXXcl SMP */
memcpy((void *)cpu_gdt_descr[cpu].address,
(void *)cpu_gdt_descr[0].address, GDT_SIZE);
}
/*
* Set up the per-thread TLS descriptor cache:
*/
memcpy(thread->tls_array, &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN],
GDT_ENTRY_TLS_ENTRIES * 8);
cpu_gdt_init(&cpu_gdt_descr[cpu]);
/*
* Delete NT
*/
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
/*
* Set up and load the per-CPU TSS and LDT
*/
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
if (current->mm)
BUG();
enter_lazy_tlb(&init_mm, current);
load_esp0(t, thread);
load_LDT(&init_mm.context);
flush_page_update_queue();
/* Clear %fs and %gs. */
asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
/* 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
/*
* Force FPU initialization:
*/
current_thread_info()->status = 0;
current->used_math = 0;
mxcsr_feature_mask_init();
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,479 @@
/******************************************************************************
* evtchn.c
*
* Communication via Xen event channels.
*
* Copyright (c) 2002-2004, K A Fraser
*/
#include <linux/config.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/atomic.h>
#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/synch_bitops.h>
#include <asm/hypervisor.h>
#include <asm/hypervisor-ifs/event_channel.h>
#include <asm/hypervisor-ifs/physdev.h>
#include <asm-xen/ctrl_if.h>
/*
* This lock protects updates to the following mapping and reference-count
* arrays. The lock does not need to be acquired to read the mapping tables.
*/
static spinlock_t irq_mapping_update_lock;
/* IRQ <-> event-channel mappings. */
static int evtchn_to_irq[NR_EVENT_CHANNELS];
static int irq_to_evtchn[NR_IRQS];
/* IRQ <-> VIRQ mapping. */
static int virq_to_irq[NR_VIRQS];
/* Reference counts for bindings to IRQs. */
static int irq_bindcount[NR_IRQS];
/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
static unsigned long pirq_needs_unmask_notify[NR_PIRQS/sizeof(unsigned long)];
/* Upcall to generic IRQ layer. */
extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
#define VALID_EVTCHN(_chn) ((_chn) != -1)
void evtchn_do_upcall(struct pt_regs *regs)
{
unsigned long l1, l2;
unsigned int l1i, l2i, port;
int irq;
unsigned long flags;
shared_info_t *s = HYPERVISOR_shared_info;
local_irq_save(flags);
while ( s->vcpu_data[0].evtchn_upcall_pending )
{
s->vcpu_data[0].evtchn_upcall_pending = 0;
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
l1 = xchg(&s->evtchn_pending_sel, 0);
while ( (l1i = ffs(l1)) != 0 )
{
l1i--;
l1 &= ~(1 << l1i);
l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
while ( (l2i = ffs(l2)) != 0 )
{
l2i--;
l2 &= ~(1 << l2i);
port = (l1i << 5) + l2i;
if ( (irq = evtchn_to_irq[port]) != -1 )
do_IRQ(irq, regs);
else
evtchn_device_upcall(port);
}
}
}
local_irq_restore(flags);
}
static int find_unbound_irq(void)
{
int irq;
for ( irq = 0; irq < NR_IRQS; irq++ )
if ( irq_bindcount[irq] == 0 )
break;
if ( irq == NR_IRQS )
panic("No available IRQ to bind to: increase NR_IRQS!\n");
return irq;
}
int bind_virq_to_irq(int virq)
{
evtchn_op_t op;
int evtchn, irq;
spin_lock(&irq_mapping_update_lock);
if ( (irq = virq_to_irq[virq]) == -1 )
{
op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = virq;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
panic("Failed to bind virtual IRQ %d\n", virq);
evtchn = op.u.bind_virq.port;
irq = find_unbound_irq();
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
virq_to_irq[virq] = irq;
}
irq_bindcount[irq]++;
spin_unlock(&irq_mapping_update_lock);
return irq;
}
void unbind_virq_from_irq(int virq)
{
evtchn_op_t op;
int irq = virq_to_irq[virq];
int evtchn = irq_to_evtchn[irq];
spin_lock(&irq_mapping_update_lock);
if ( --irq_bindcount[irq] == 0 )
{
op.cmd = EVTCHNOP_close;
op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
panic("Failed to unbind virtual IRQ %d\n", virq);
evtchn_to_irq[evtchn] = -1;
irq_to_evtchn[irq] = -1;
virq_to_irq[virq] = -1;
}
spin_unlock(&irq_mapping_update_lock);
}
int bind_evtchn_to_irq(int evtchn)
{
int irq;
spin_lock(&irq_mapping_update_lock);
if ( (irq = evtchn_to_irq[evtchn]) == -1 )
{
irq = find_unbound_irq();
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
}
irq_bindcount[irq]++;
spin_unlock(&irq_mapping_update_lock);
return irq;
}
void unbind_evtchn_from_irq(int evtchn)
{
int irq = evtchn_to_irq[evtchn];
spin_lock(&irq_mapping_update_lock);
if ( --irq_bindcount[irq] == 0 )
{
evtchn_to_irq[evtchn] = -1;
irq_to_evtchn[irq] = -1;
}
spin_unlock(&irq_mapping_update_lock);
}
/*
* Interface to generic handling in irq.c
*/
static unsigned int startup_dynirq(unsigned int irq)
{
unmask_evtchn(irq_to_evtchn[irq]);
return 0;
}
static void shutdown_dynirq(unsigned int irq)
{
mask_evtchn(irq_to_evtchn[irq]);
}
static void enable_dynirq(unsigned int irq)
{
unmask_evtchn(irq_to_evtchn[irq]);
}
static void disable_dynirq(unsigned int irq)
{
mask_evtchn(irq_to_evtchn[irq]);
}
static void ack_dynirq(unsigned int irq)
{
mask_evtchn(irq_to_evtchn[irq]);
clear_evtchn(irq_to_evtchn[irq]);
}
static void end_dynirq(unsigned int irq)
{
if ( !(irq_desc[irq].status & IRQ_DISABLED) )
unmask_evtchn(irq_to_evtchn[irq]);
}
static struct hw_interrupt_type dynirq_type = {
"Dynamic-irq",
startup_dynirq,
shutdown_dynirq,
enable_dynirq,
disable_dynirq,
ack_dynirq,
end_dynirq,
NULL
};
static inline void pirq_unmask_notify(int pirq)
{
physdev_op_t op;
if ( unlikely(test_bit(pirq, &pirq_needs_unmask_notify[0])) )
{
op.cmd = PHYSDEVOP_IRQ_UNMASK_NOTIFY;
(void)HYPERVISOR_physdev_op(&op);
}
}
static inline void pirq_query_unmask(int pirq)
{
physdev_op_t op;
op.cmd = PHYSDEVOP_IRQ_STATUS_QUERY;
op.u.irq_status_query.irq = pirq;
(void)HYPERVISOR_physdev_op(&op);
clear_bit(pirq, &pirq_needs_unmask_notify[0]);
if ( op.u.irq_status_query.flags & PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY )
set_bit(pirq, &pirq_needs_unmask_notify[0]);
}
/*
* On startup, if there is no action associated with the IRQ then we are
* probing. In this case we should not share with others as it will confuse us.
*/
#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL)
static unsigned int startup_pirq(unsigned int irq)
{
evtchn_op_t op;
int evtchn;
op.cmd = EVTCHNOP_bind_pirq;
op.u.bind_pirq.pirq = irq;
/* NB. We are happy to share unless we are probing. */
op.u.bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
{
if ( !probing_irq(irq) ) /* Some failures are expected when probing. */
printk(KERN_INFO "Failed to obtain physical IRQ %d\n", irq);
return 0;
}
evtchn = op.u.bind_pirq.port;
pirq_query_unmask(irq_to_pirq(irq));
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
unmask_evtchn(evtchn);
pirq_unmask_notify(irq_to_pirq(irq));
return 0;
}
static void shutdown_pirq(unsigned int irq)
{
evtchn_op_t op;
int evtchn = irq_to_evtchn[irq];
if ( !VALID_EVTCHN(evtchn) )
return;
mask_evtchn(evtchn);
op.cmd = EVTCHNOP_close;
op.u.close.dom = DOMID_SELF;
op.u.close.port = evtchn;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
panic("Failed to unbind physical IRQ %d\n", irq);
evtchn_to_irq[evtchn] = -1;
irq_to_evtchn[irq] = -1;
}
static void enable_pirq(unsigned int irq)
{
int evtchn = irq_to_evtchn[irq];
if ( !VALID_EVTCHN(evtchn) )
return;
unmask_evtchn(evtchn);
pirq_unmask_notify(irq_to_pirq(irq));
}
static void disable_pirq(unsigned int irq)
{
int evtchn = irq_to_evtchn[irq];
if ( !VALID_EVTCHN(evtchn) )
return;
mask_evtchn(evtchn);
}
static void ack_pirq(unsigned int irq)
{
int evtchn = irq_to_evtchn[irq];
if ( !VALID_EVTCHN(evtchn) )
return;
mask_evtchn(evtchn);
clear_evtchn(evtchn);
}
static void end_pirq(unsigned int irq)
{
int evtchn = irq_to_evtchn[irq];
if ( !VALID_EVTCHN(evtchn) )
return;
if ( !(irq_desc[irq].status & IRQ_DISABLED) )
{
unmask_evtchn(evtchn);
pirq_unmask_notify(irq_to_pirq(irq));
}
}
static struct hw_interrupt_type pirq_type = {
"Phys-irq",
startup_pirq,
shutdown_pirq,
enable_pirq,
disable_pirq,
ack_pirq,
end_pirq,
NULL
};
static irqreturn_t misdirect_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
/* nothing */
return IRQ_HANDLED;
}
static struct irqaction misdirect_action = {
misdirect_interrupt,
SA_INTERRUPT,
0,
"misdirect",
NULL,
NULL
};
void irq_suspend(void)
{
int virq, irq, evtchn;
/* Unbind VIRQs from event channels. */
for ( virq = 0; virq < NR_VIRQS; virq++ )
{
if ( (irq = virq_to_irq[virq]) == -1 )
continue;
evtchn = irq_to_evtchn[irq];
/* Mark the event channel as unused in our table. */
evtchn_to_irq[evtchn] = -1;
irq_to_evtchn[irq] = -1;
}
/*
* We should now be unbound from all event channels. Stale bindings to
* PIRQs and/or inter-domain event channels will cause us to barf here.
*/
for ( evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++ )
if ( evtchn_to_irq[evtchn] != -1 )
panic("Suspend attempted while bound to evtchn %d.\n", evtchn);
}
void irq_resume(void)
{
evtchn_op_t op;
int virq, irq, evtchn;
for ( evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++ )
mask_evtchn(evtchn); /* New event-channel space is not 'live' yet. */
for ( virq = 0; virq < NR_VIRQS; virq++ )
{
if ( (irq = virq_to_irq[virq]) == -1 )
continue;
/* Get a new binding from Xen. */
op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = virq;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
panic("Failed to bind virtual IRQ %d\n", virq);
evtchn = op.u.bind_virq.port;
/* Record the new mapping. */
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
/* Ready for use. */
unmask_evtchn(evtchn);
}
}
void __init init_IRQ(void)
{
int i;
spin_lock_init(&irq_mapping_update_lock);
/* No VIRQ -> IRQ mappings. */
for ( i = 0; i < NR_VIRQS; i++ )
virq_to_irq[i] = -1;
/* No event-channel -> IRQ mappings. */
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
{
evtchn_to_irq[i] = -1;
mask_evtchn(i); /* No event channels are 'live' right now. */
}
/* No IRQ -> event-channel mappings. */
for ( i = 0; i < NR_IRQS; i++ )
irq_to_evtchn[i] = -1;
for ( i = 0; i < NR_DYNIRQS; i++ )
{
/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
irq_bindcount[dynirq_to_irq(i)] = 0;
irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED;
irq_desc[dynirq_to_irq(i)].action = 0;
irq_desc[dynirq_to_irq(i)].depth = 1;
irq_desc[dynirq_to_irq(i)].handler = &dynirq_type;
}
for ( i = 0; i < NR_PIRQS; i++ )
{
/* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */
irq_bindcount[pirq_to_irq(i)] = 1;
irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED;
irq_desc[pirq_to_irq(i)].action = 0;
irq_desc[pirq_to_irq(i)].depth = 1;
irq_desc[pirq_to_irq(i)].handler = &pirq_type;
}
(void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
/* This needs to be done early, but after the IRQ subsystem is alive. */
ctrl_if_init();
}
@@ -0,0 +1,191 @@
.section __xen_guest
.asciz "GUEST_OS=linux,GUEST_VER=2.6,XEN_VER=1.3"
.text
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/thread_info.h>
#include <asm/asm_offsets.h>
#include <asm/hypervisor-ifs/arch-x86_32.h>
/*
* References to members of the new_cpu_data structure.
*/
#define X86 new_cpu_data+CPUINFO_x86
#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor
#define X86_MODEL new_cpu_data+CPUINFO_x86_model
#define X86_MASK new_cpu_data+CPUINFO_x86_mask
#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math
#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level
#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability
#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id
/* Offsets in start_info structure */
#define MOD_START 24
#define MOD_LEN 28
ENTRY(startup_32)
cld
/* Set up the stack pointer */
lss stack_start,%esp
/* Copy initrd somewhere safe before it's clobbered by BSS. */
mov MOD_LEN(%esi),%ecx
shr $2,%ecx
jz 2f /* bail from copy loop if no initrd */
mov $_end,%edi
add MOD_LEN(%esi),%edi
mov MOD_START(%esi),%eax
add MOD_LEN(%esi),%eax
1: sub $4,%eax
sub $4,%edi
mov (%eax),%ebx
mov %ebx,(%edi)
loop 1b
mov %edi,MOD_START(%esi)
/* Clear BSS first so that there are no surprises... */
2: xorl %eax,%eax
movl $__bss_start,%edi
movl $__bss_stop,%ecx
subl %edi,%ecx
rep stosb
/* Copy the necessary stuff from start_info structure. */
mov $start_info_union,%edi
mov $128,%ecx
rep movsl
checkCPUtype:
/* get vendor info */
xorl %eax,%eax # call CPUID with 0 -> return vendor ID
cpuid
movl %eax,X86_CPUID # save CPUID level
movl %ebx,X86_VENDOR_ID # lo 4 chars
movl %edx,X86_VENDOR_ID+4 # next 4 chars
movl %ecx,X86_VENDOR_ID+8 # last 4 chars
movl $1,%eax # Use the CPUID instruction to get CPU type
cpuid
movb %al,%cl # save reg for future use
andb $0x0f,%ah # mask processor family
movb %ah,X86
andb $0xf0,%al # mask model
shrb $4,%al
movb %al,X86_MODEL
andb $0x0f,%cl # mask mask revision
movb %cl,X86_MASK
movl %edx,X86_CAPABILITY
xorl %eax,%eax # Clear FS/GS and LDT
movl %eax,%fs
movl %eax,%gs
cld # gcc2 wants the direction flag cleared at all times
call start_kernel
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
ENTRY(lgdt_finish)
movl $(__KERNEL_DS),%eax # reload all the segment registers
movw %ax,%ss # after changing gdt.
movl $(__USER_DS),%eax # DS/ES contains default USER segment
movw %ax,%ds
movw %ax,%es
popl %eax # reload CS by intersegment return
pushl $(__KERNEL_CS)
pushl %eax
lret
ENTRY(stack_start)
.long init_thread_union+THREAD_SIZE
.long __BOOT_DS
# XXXcl
.globl idt_descr
.globl cpu_gdt_descr
ALIGN
.word 0 # 32-bit align idt_desc.address
idt_descr:
.word IDT_ENTRIES*8-1 # idt contains 256 entries
.long idt_table
# XXXcl
# boot GDT descriptor (later on used by CPU#0):
.word 0 # 32 bit align gdt_desc.address
cpu_gdt_descr:
.word GDT_SIZE
.long cpu_gdt_table
.fill NR_CPUS-1,8,0 # space for the other GDT descriptors
.org 0x1000
ENTRY(empty_zero_page)
.org 0x2000
ENTRY(swapper_pg_dir)
.org 0x3000
ENTRY(cpu_gdt_table)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* 0x0b reserved */
.quad 0x0000000000000000 /* 0x13 reserved */
.quad 0x0000000000000000 /* 0x1b reserved */
.quad 0x0000000000000000 /* 0x20 unused */
.quad 0x0000000000000000 /* 0x28 unused */
.quad 0x0000000000000000 /* 0x33 TLS entry 1 */
.quad 0x0000000000000000 /* 0x3b TLS entry 2 */
.quad 0x0000000000000000 /* 0x43 TLS entry 3 */
.quad 0x0000000000000000 /* 0x4b reserved */
.quad 0x0000000000000000 /* 0x53 reserved */
.quad 0x0000000000000000 /* 0x5b reserved */
.quad 0x00cfbb000000c3ff /* 0x60 kernel 4GB code at 0x00000000 */
.quad 0x00cfb3000000c3ff /* 0x68 kernel 4GB data at 0x00000000 */
.quad 0x00cffb000000c3ff /* 0x73 user 4GB code at 0x00000000 */
.quad 0x00cff3000000c3ff /* 0x7b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* 0x80 TSS descriptor */
.quad 0x0000000000000000 /* 0x88 LDT descriptor */
/* Segments used for calling PnP BIOS */
.quad 0x0000000000000000 /* 0x90 32-bit code */
.quad 0x0000000000000000 /* 0x98 16-bit code */
.quad 0x0000000000000000 /* 0xa0 16-bit data */
.quad 0x0000000000000000 /* 0xa8 16-bit data */
.quad 0x0000000000000000 /* 0xb0 16-bit data */
/*
* The APM segments have byte granularity and their bases
* and limits are set at run time.
*/
.quad 0x0000000000000000 /* 0xb8 APM CS code */
.quad 0x0000000000000000 /* 0xc0 APM CS 16 code (16 bit) */
.quad 0x0000000000000000 /* 0xc8 APM DS data */
.quad 0x0000000000000000 /* 0xd0 - unused */
.quad 0x0000000000000000 /* 0xd8 - unused */
.quad 0x0000000000000000 /* 0xe0 - unused */
.quad 0x0000000000000000 /* 0xe8 - unused */
.quad 0x0000000000000000 /* 0xf0 - unused */
.quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
.fill GDT_ENTRIES-32,8,0
.org 0x4000
ENTRY(default_ldt)
.org 0x5000
/*
* Real beginning of normal "text" segment
*/
ENTRY(stext)
ENTRY(_stext)
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,274 @@
/*
* linux/kernel/ldt.c
*
* Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/ldt.h>
#include <asm/desc.h>
#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
static void flush_ldt(void *null)
{
if (current->active_mm)
load_LDT(&current->active_mm->context);
}
#endif
static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
{
void *oldldt;
void *newldt;
int oldsize;
if (mincount <= pc->size)
return 0;
oldsize = pc->size;
mincount = (mincount+511)&(~511);
if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
else
newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
if (!newldt)
return -ENOMEM;
if (oldsize)
memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
oldldt = pc->ldt;
memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
pc->ldt = newldt;
wmb();
pc->size = mincount;
wmb();
if (reload) {
#ifdef CONFIG_SMP
cpumask_t mask;
preempt_disable();
#endif
make_pages_readonly(pc->ldt, (pc->size * LDT_ENTRY_SIZE) /
PAGE_SIZE);
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, 0, 1, 1);
preempt_enable();
#endif
}
if (oldsize) {
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);
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;
}
/*
* No need to lock the MM as we are the last user
*/
void destroy_context(struct mm_struct *mm)
{
if (mm->context.size) {
if (mm == current->active_mm)
clear_LDT();
make_pages_writeable(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)
return err;
if (size != bytecount) {
/* zero-fill the rest */
clear_user(ptr+size, bytecount-size);
}
return bytecount;
}
static int read_default_ldt(void __user * ptr, unsigned long bytecount)
{
int err;
unsigned long size;
void *address;
err = 0;
address = &default_ldt[0];
size = 5*sizeof(struct desc_struct);
if (size > bytecount)
size = bytecount;
err = size;
if (copy_to_user(ptr, address, size))
err = -EFAULT;
return err;
}
static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
{
struct mm_struct * mm = current->mm;
__u32 entry_1, entry_2, *lp;
unsigned long phys_lp, max_limit;
int error;
struct user_desc ldt_info;
error = -EINVAL;
if (bytecount != sizeof(ldt_info))
goto out;
error = -EFAULT;
if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
goto out;
error = -EINVAL;
if (ldt_info.entry_number >= LDT_ENTRIES)
goto out;
if (ldt_info.contents == 3) {
if (oldmode)
goto out;
if (ldt_info.seg_not_present == 0)
goto out;
}
/*
* This makes our tests for overlap with Xen space
* easier. There's no good reason to have a user segment
* starting this high anyway.
*/
if (ldt_info.base_addr >= PAGE_OFFSET)
goto out;
down(&mm->context.sem);
if (ldt_info.entry_number >= mm->context.size) {
error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
if (error < 0)
goto out_unlock;
}
lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
phys_lp = arbitrary_virt_to_phys(lp);
/* Allow LDTs to be cleared by the user. */
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
if (oldmode || LDT_empty(&ldt_info)) {
entry_1 = 0;
entry_2 = 0;
goto install;
}
}
max_limit = HYPERVISOR_VIRT_START - ldt_info.base_addr;
if (ldt_info.limit_in_pages)
max_limit >>= PAGE_SHIFT;
max_limit--;
if ((ldt_info.limit & 0xfffff) > (max_limit & 0xfffff))
ldt_info.limit = max_limit;
entry_1 = LDT_entry_a(&ldt_info);
entry_2 = LDT_entry_b(&ldt_info);
if (oldmode)
entry_2 &= ~(1 << 20);
/* Install the new entry ... */
install:
error = HYPERVISOR_update_descriptor(phys_lp, entry_1, entry_2);
out_unlock:
up(&mm->context.sem);
out:
return error;
}
asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
{
int ret = -ENOSYS;
switch (func) {
case 0:
ret = read_ldt(ptr, bytecount);
break;
case 1:
ret = write_ldt(ptr, bytecount, 1);
break;
case 2:
ret = read_default_ldt(ptr, bytecount);
break;
case 0x11:
ret = write_ldt(ptr, bytecount, 0);
break;
}
return ret;
}
@@ -0,0 +1,782 @@
/*
* linux/arch/i386/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
* This file handles the architecture-dependent parts of process handling..
*/
#include <stdarg.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/elfcore.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/mc146818rtc.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/ptrace.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ldt.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/irq.h>
#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif
#include <linux/irq.h>
#include <linux/err.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
int hlt_counter;
/*
* Return saved PC of a blocked thread.
*/
unsigned long thread_saved_pc(struct task_struct *tsk)
{
return ((unsigned long *)tsk->thread.esp)[3];
}
/*
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
void disable_hlt(void)
{
hlt_counter++;
}
EXPORT_SYMBOL(disable_hlt);
void enable_hlt(void)
{
hlt_counter--;
}
EXPORT_SYMBOL(enable_hlt);
/*
* We use this if we don't have any better
* idle routine..
*/
void default_idle(void)
{
if (!hlt_counter && current_cpu_data.hlt_works_ok) {
local_irq_disable();
if (!need_resched())
safe_halt();
else
local_irq_enable();
}
}
/*
* On SMP it's slightly faster (but much more power-consuming!)
* to poll the ->work.need_resched flag instead of waiting for the
* cross-CPU IPI to arrive. Use this option with caution.
*/
static void poll_idle (void)
{
int oldval;
local_irq_enable();
/*
* Deal with another CPU just having chosen a thread to
* run here:
*/
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
set_thread_flag(TIF_POLLING_NRFLAG);
asm volatile(
"2:"
"testl %0, %1;"
"rep; nop;"
"je 2b;"
: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
clear_thread_flag(TIF_POLLING_NRFLAG);
} else {
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)
{
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
irq_stat[smp_processor_id()].idle_timestamp = jiffies;
idle();
}
schedule();
}
}
/*
* This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
* which can obviate IPI to trigger checking of need_resched.
* We execute MONITOR against need_resched and enter optimized wait state
* through MWAIT. Whenever someone changes need_resched, we would be woken
* up from MWAIT (without an IPI).
*/
static void mwait_idle(void)
{
local_irq_enable();
if (!need_resched()) {
set_thread_flag(TIF_POLLING_NRFLAG);
do {
__monitor((void *)&current_thread_info()->flags, 0, 0);
if (need_resched())
break;
__mwait(0, 0);
} while (!need_resched());
clear_thread_flag(TIF_POLLING_NRFLAG);
}
}
void __init select_idle_routine(const struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_MWAIT)) {
printk("monitor/mwait feature present.\n");
/*
* Skip, if setup has overridden idle.
* Also, take care of system with asymmetric CPUs.
* Use, mwait_idle only if all cpus support it.
* If not, we fallback to default_idle()
*/
if (!pm_idle) {
printk("using mwait in idle threads.\n");
pm_idle = mwait_idle;
}
return;
}
pm_idle = xen_cpu_idle;
return;
}
static int __init idle_setup (char *str)
{
if (!strncmp(str, "poll", 4)) {
printk("using polling idle threads.\n");
pm_idle = poll_idle;
#ifdef CONFIG_X86_SMP
if (smp_num_siblings > 1)
printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
#endif
} else if (!strncmp(str, "halt", 4)) {
printk("using halt in idle threads.\n");
pm_idle = default_idle;
}
return 1;
}
__setup("idle=", idle_setup);
void show_regs(struct pt_regs * regs)
{
printk("\n");
printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id());
print_symbol("EIP is at %s\n", regs->eip);
if (regs->xcs & 2)
printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
printk(" EFLAGS: %08lx %s (%s)\n",regs->eflags, print_tainted(),UTS_RELEASE);
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
regs->eax,regs->ebx,regs->ecx,regs->edx);
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
regs->esi, regs->edi, regs->ebp);
printk(" DS: %04x ES: %04x\n",
0xffff & regs->xds,0xffff & regs->xes);
show_trace(NULL, &regs->esp);
}
/*
* This gets run with %ebx containing the
* function to call, and %edx containing
* the "args".
*/
extern void kernel_thread_helper(void);
__asm__(".section .text\n"
".align 4\n"
"kernel_thread_helper:\n\t"
"movl %edx,%eax\n\t"
"pushl %edx\n\t"
"call *%ebx\n\t"
"pushl %eax\n\t"
"call do_exit\n"
".previous");
/*
* Create a kernel thread
*/
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.ebx = (unsigned long) fn;
regs.edx = (unsigned long) arg;
regs.xds = __USER_DS;
regs.xes = __USER_DS;
regs.orig_eax = -1;
regs.eip = (unsigned long) kernel_thread_helper;
regs.xcs = __KERNEL_CS;
regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
/* Ok, create the new process.. */
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
/*
* Free current thread data structures etc..
*/
void exit_thread(void)
{
struct task_struct *tsk = current;
/* The process may have allocated an io port bitmap... nuke it. */
if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) {
int cpu = get_cpu();
struct tss_struct *tss = init_tss + cpu;
kfree(tsk->thread.io_bitmap_ptr);
tsk->thread.io_bitmap_ptr = NULL;
tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
put_cpu();
}
}
void flush_thread(void)
{
struct task_struct *tsk = current;
memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
/*
* Forget coprocessor state..
*/
clear_fpu(tsk);
tsk->used_math = 0;
}
void release_thread(struct task_struct *dead_task)
{
if (dead_task->mm) {
// temporary debugging check
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();
}
}
release_x86_irqs(dead_task);
}
/*
* This gets called before we allocate a new thread and copy
* the current task into it.
*/
void prepare_to_copy(struct task_struct *tsk)
{
unlazy_fpu(tsk);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
unsigned long unused,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
struct task_struct *tsk;
int err;
childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
struct_cpy(childregs, regs);
childregs->eax = 0;
childregs->esp = esp;
p->set_child_tid = p->clear_child_tid = NULL;
p->thread.esp = (unsigned long) childregs;
p->thread.esp0 = (unsigned long) (childregs+1);
p->thread.eip = (unsigned long) ret_from_fork;
savesegment(fs,p->thread.fs);
savesegment(gs,p->thread.gs);
tsk = current;
if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) {
p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
if (!p->thread.io_bitmap_ptr)
return -ENOMEM;
memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr,
IO_BITMAP_BYTES);
}
/*
* Set a new TLS for the child thread?
*/
if (clone_flags & CLONE_SETTLS) {
struct desc_struct *desc;
struct user_desc info;
int idx;
err = -EFAULT;
if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
goto out;
err = -EINVAL;
if (LDT_empty(&info))
goto out;
idx = info.entry_number;
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
goto out;
desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
desc->a = LDT_entry_a(&info);
desc->b = LDT_entry_b(&info);
}
err = 0;
out:
if (err && p->thread.io_bitmap_ptr)
kfree(p->thread.io_bitmap_ptr);
return err;
}
/*
* fill in the user structure for a core dump..
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
{
int i;
/* changed the size calculations - should hopefully work better. lbt */
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
dump->u_dsize -= dump->u_tsize;
dump->u_ssize = 0;
for (i = 0; i < 8; i++)
dump->u_debugreg[i] = current->thread.debugreg[i];
if (dump->start_stack < TASK_SIZE)
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
dump->regs.ebx = regs->ebx;
dump->regs.ecx = regs->ecx;
dump->regs.edx = regs->edx;
dump->regs.esi = regs->esi;
dump->regs.edi = regs->edi;
dump->regs.ebp = regs->ebp;
dump->regs.eax = regs->eax;
dump->regs.ds = regs->xds;
dump->regs.es = regs->xes;
savesegment(fs,dump->regs.fs);
savesegment(gs,dump->regs.gs);
dump->regs.orig_eax = regs->orig_eax;
dump->regs.eip = regs->eip;
dump->regs.cs = regs->xcs;
dump->regs.eflags = regs->eflags;
dump->regs.esp = regs->esp;
dump->regs.ss = regs->xss;
dump->u_fpvalid = dump_fpu (regs, &dump->i387);
}
/*
* Capture the user space registers if the task is not running (in user space)
*/
int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
{
struct pt_regs ptregs;
ptregs = *(struct pt_regs *)
((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs));
ptregs.xcs &= 0xffff;
ptregs.xds &= 0xffff;
ptregs.xes &= 0xffff;
ptregs.xss &= 0xffff;
elf_core_copy_regs(regs, &ptregs);
return 1;
}
/*
* 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,yn) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
* (as a call from the fsave or fwait in effect) rather than to
* the wrong process. Lazy FP saving no longer makes any sense
* with modern CPU's, and this simplifies a lot of things (SMP
* and UP become the same).
*
* NOTE! We used to use the x86 hardware context switching. The
* reason for not using it any more becomes apparent when you
* try to recover gracefully from saved state that is no longer
* valid (stale segment register values in particular). With the
* hardware task-switch, there is no way to fix up bad state in
* a reasonable manner.
*
* The fact that Intel documents the hardware task-switching to
* be slow is a fairly red herring - this code is not noticeably
* faster. However, there _is_ some room for improvement here,
* so the performance issues may eventually be a valid point.
* More important, however, is the fact that this allows us much
* more flexibility.
*
* The return value (in %eax) will be the "prev" task after
* the task-switch, and shows up in ret_from_fork in entry.S,
* for example.
*/
struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
*next = &next_p->thread;
int cpu = smp_processor_id();
struct tss_struct *tss = init_tss + cpu;
unsigned long flags;
local_irq_save(flags);
/*
* Save away %fs and %gs. No need to save %es and %ds, as
* those are always kernel segments while inside the kernel.
*/
asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
/*
* We clobber FS and GS here so that we avoid a GPF when
* restoring previous task's FS/GS values in Xen when the LDT
* is switched. If we don't do this then we can end up
* erroneously re-flushing the page-update queue when we
* 'execute_multicall_list'.
*/
__asm__ __volatile__ (
"xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs" : : :
"eax" );
flush_page_update_queue();
/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
__unlazy_fpu(prev_p);
/*
* Reload esp0, LDT and the page table pointer:
*/
load_esp0(tss, next);
/*
* Load the per-thread Thread-Local Storage descriptor.
*/
load_TLS(next, cpu);
local_irq_restore(flags);
/*
* Restore %fs and %gs if needed.
*/
if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
loadsegment(fs, next->fs);
loadsegment(gs, next->gs);
}
/*
* Now maybe reload the debug registers
*/
if (unlikely(next->debugreg[7])) {
loaddebug(next, 0);
loaddebug(next, 1);
loaddebug(next, 2);
loaddebug(next, 3);
/* no 4 and 5 */
loaddebug(next, 6);
loaddebug(next, 7);
}
if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
if (next->io_bitmap_ptr) {
/*
* 4 cachelines copy ... not good, but not that
* bad either. Anyone got something better?
* This only affects processes which use ioperm().
* [Putting the TSSs into 4k-tlb mapped regions
* and playing VM tricks to switch the IO bitmap
* is not really acceptable.]
*/
memcpy(tss->io_bitmap, next->io_bitmap_ptr,
IO_BITMAP_BYTES);
tss->io_bitmap_base = IO_BITMAP_OFFSET;
} else
/*
* a bitmap offset pointing outside of the TSS limit
* causes a nicely controllable SIGSEGV if a process
* tries to use a port IO instruction. The first
* sys_ioperm() call sets up the bitmap properly.
*/
tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
}
return prev_p;
}
asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}
asmlinkage int sys_clone(struct pt_regs regs)
{
unsigned long clone_flags;
unsigned long newsp;
int __user *parent_tidptr, *child_tidptr;
clone_flags = regs.ebx;
newsp = regs.ecx;
parent_tidptr = (int __user *)regs.edx;
child_tidptr = (int __user *)regs.edi;
if (!newsp)
newsp = regs.esp;
return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, parent_tidptr, child_tidptr);
}
/*
* This is trivial, and on the face of it looks like it
* could equally well be done in user mode.
*
* Not so, for quite unobvious reasons - register pressure.
* In user mode vfork() cannot have a stack frame, and if
* done by calling the "clone()" system call directly, you
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
asmlinkage int sys_vfork(struct pt_regs regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}
/*
* sys_execve() executes a new program.
*/
asmlinkage int sys_execve(struct pt_regs regs)
{
int error;
char * filename;
filename = getname((char __user *) regs.ebx);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename,
(char __user * __user *) regs.ecx,
(char __user * __user *) regs.edx,
&regs);
if (error == 0) {
current->ptrace &= ~PT_DTRACE;
/* Make sure we don't return using sysenter.. */
set_thread_flag(TIF_IRET);
}
putname(filename);
out:
return error;
}
#define top_esp (THREAD_SIZE - sizeof(unsigned long))
#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long))
unsigned long get_wchan(struct task_struct *p)
{
unsigned long ebp, esp, eip;
unsigned long stack_page;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long)p->thread_info;
esp = p->thread.esp;
if (!stack_page || esp < stack_page || esp > top_esp+stack_page)
return 0;
/* include/asm-i386/system.h:switch_to() pushes ebp last. */
ebp = *(unsigned long *) esp;
do {
if (ebp < stack_page || ebp > top_ebp+stack_page)
return 0;
eip = *(unsigned long *) (ebp+4);
if (!in_sched_functions(eip))
return eip;
ebp = *(unsigned long *) ebp;
} while (count++ < 16);
return 0;
}
/*
* sys_alloc_thread_area: get a yet unused TLS descriptor index.
*/
static int get_free_idx(void)
{
struct thread_struct *t = &current->thread;
int idx;
for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
if (desc_empty(t->tls_array + idx))
return idx + GDT_ENTRY_TLS_MIN;
return -ESRCH;
}
/*
* Set a given TLS descriptor:
*/
asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
{
struct thread_struct *t = &current->thread;
struct user_desc info;
struct desc_struct *desc;
int cpu, idx;
if (copy_from_user(&info, u_info, sizeof(info)))
return -EFAULT;
idx = info.entry_number;
/*
* index -1 means the kernel should try to find and
* allocate an empty descriptor:
*/
if (idx == -1) {
idx = get_free_idx();
if (idx < 0)
return idx;
if (put_user(idx, &u_info->entry_number))
return -EFAULT;
}
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;
desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
/*
* We must not get preempted while modifying the TLS.
*/
cpu = get_cpu();
if (LDT_empty(&info)) {
desc->a = 0;
desc->b = 0;
} else {
desc->a = LDT_entry_a(&info);
desc->b = LDT_entry_b(&info);
}
load_TLS(t, cpu);
put_cpu();
return 0;
}
/*
* Get the current Thread-Local Storage area:
*/
#define GET_BASE(desc) ( \
(((desc)->a >> 16) & 0x0000ffff) | \
(((desc)->b << 16) & 0x00ff0000) | \
( (desc)->b & 0xff000000) )
#define GET_LIMIT(desc) ( \
((desc)->a & 0x0ffff) | \
((desc)->b & 0xf0000) )
#define GET_32BIT(desc) (((desc)->b >> 22) & 1)
#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3)
#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1)
#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1)
#define GET_PRESENT(desc) (((desc)->b >> 15) & 1)
#define GET_USEABLE(desc) (((desc)->b >> 20) & 1)
asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
{
struct user_desc info;
struct desc_struct *desc;
int idx;
if (get_user(idx, &u_info->entry_number))
return -EFAULT;
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;
desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
info.entry_number = idx;
info.base_addr = GET_BASE(desc);
info.limit = GET_LIMIT(desc);
info.seg_32bit = GET_32BIT(desc);
info.contents = GET_CONTENTS(desc);
info.read_exec_only = !GET_WRITABLE(desc);
info.limit_in_pages = GET_LIMIT_PAGES(desc);
info.seg_not_present = !GET_PRESENT(desc);
info.useable = GET_USEABLE(desc);
if (copy_to_user(u_info, &info, sizeof(info)))
return -EFAULT;
return 0;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,624 @@
/*
* linux/arch/i386/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
*/
#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/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/suspend.h>
#include <linux/elf.h>
#include <asm/processor.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#include "sigframe.h"
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
struct pt_regs * regs = (struct pt_regs *) &history0;
sigset_t saveset;
mask &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
saveset = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
regs->eax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
}
}
asmlinkage int
sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
{
struct pt_regs * regs = (struct pt_regs *) &unewset;
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);
regs->eax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
}
}
asmlinkage int
sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
if (act) {
old_sigset_t mask;
if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT;
__get_user(new_ka.sa.sa_flags, &act->sa_flags);
__get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
__put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
return -EFAULT;
__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
}
asmlinkage int
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
{
struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->esp);
}
/*
* Do a signal return; undo the signal stack.
*/
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
{
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)
#define COPY_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp; }
#define COPY_SEG_STRICT(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp|3; }
#define GET_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
loadsegment(seg,tmp); }
#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | X86_EFLAGS_DF | \
X86_EFLAGS_TF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \
X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF)
GET_SEG(gs);
GET_SEG(fs);
COPY_SEG(es);
COPY_SEG(ds);
COPY(edi);
COPY(esi);
COPY(ebp);
COPY(esp);
COPY(ebx);
COPY(edx);
COPY(ecx);
COPY(eip);
COPY_SEG_STRICT(cs);
COPY_SEG_STRICT(ss);
{
unsigned int tmpflags;
err |= __get_user(tmpflags, &sc->eflags);
regs->eflags = (regs->eflags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
regs->orig_eax = -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);
}
}
err |= __get_user(*peax, &sc->eax);
return err;
badframe:
return 1;
}
asmlinkage int sys_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *) &__unused;
struct sigframe __user *frame = (struct sigframe __user *)(regs->esp - 8);
sigset_t set;
int eax;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
sizeof(frame->extramask))))
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->sc, &eax))
goto badframe;
return eax;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
asmlinkage int sys_rt_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *) &__unused;
struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs->esp - 4);
sigset_t set;
int eax;
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;
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->esp) == -EFAULT)
goto badframe;
return eax;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
/*
* Set up a signal frame.
*/
static int
setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
struct pt_regs *regs, unsigned long mask)
{
int tmp, err = 0;
tmp = 0;
__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
err |= __put_user(regs->xds, (unsigned int __user *)&sc->ds);
err |= __put_user(regs->edi, &sc->edi);
err |= __put_user(regs->esi, &sc->esi);
err |= __put_user(regs->ebp, &sc->ebp);
err |= __put_user(regs->esp, &sc->esp);
err |= __put_user(regs->ebx, &sc->ebx);
err |= __put_user(regs->edx, &sc->edx);
err |= __put_user(regs->ecx, &sc->ecx);
err |= __put_user(regs->eax, &sc->eax);
err |= __put_user(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err);
err |= __put_user(regs->eip, &sc->eip);
err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs);
err |= __put_user(regs->eflags, &sc->eflags);
err |= __put_user(regs->esp, &sc->esp_at_signal);
err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss);
tmp = save_i387(fpstate);
if (tmp < 0)
err = 1;
else
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(current->thread.cr2, &sc->cr2);
return err;
}
/*
* Determine which stack to use..
*/
static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
{
unsigned long esp;
/* Default to using normal stack */
esp = regs->esp;
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
if (sas_ss_flags(esp) == 0)
esp = current->sas_ss_sp + current->sas_ss_size;
}
/* This is the legacy signal stack switching. */
else if ((regs->xss & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
return (void __user *)((esp - frame_size) & -8ul);
}
/* These symbols are defined with the addresses in the vsyscall page.
See vsyscall-sigreturn.S. */
extern void __kernel_sigreturn, __kernel_rt_sigreturn;
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
void *restorer;
struct sigframe __user *frame;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
err |= __put_user((current_thread_info()->exec_domain
&& current_thread_info()->exec_domain->signal_invmap
&& sig < 32
? current_thread_info()->exec_domain->signal_invmap[sig]
: sig),
&frame->sig);
if (err)
goto give_sigsegv;
err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
if (err)
goto give_sigsegv;
if (_NSIG_WORDS > 1) {
err |= __copy_to_user(&frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err)
goto give_sigsegv;
restorer = &__kernel_sigreturn;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
/* Set up to return from userspace. */
err |= __put_user(restorer, &frame->pretcode);
/*
* This is popl %eax ; movl $,%eax ; int $0x80
*
* WE DO NOT USE IT ANY MORE! It's only left here for historical
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
regs->esp = (unsigned long) frame;
regs->eip = (unsigned long) ka->sa.sa_handler;
set_fs(USER_DS);
regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
regs->xcs = __USER_CS;
regs->eflags &= ~TF_MASK;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
return;
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs)
{
void *restorer;
struct rt_sigframe __user *frame;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
err |= __put_user((current_thread_info()->exec_domain
&& current_thread_info()->exec_domain->signal_invmap
&& sig < 32
? current_thread_info()->exec_domain->signal_invmap[sig]
: sig),
&frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
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(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->esp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto give_sigsegv;
/* Set up to return from userspace. */
restorer = &__kernel_rt_sigreturn;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
err |= __put_user(restorer, &frame->pretcode);
/*
* This is movl $,%eax ; int $0x80
*
* WE DO NOT USE IT ANY MORE! It's only left here for historical
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
regs->esp = (unsigned long) frame;
regs->eip = (unsigned long) ka->sa.sa_handler;
set_fs(USER_DS);
regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
regs->xcs = __USER_CS;
regs->eflags &= ~TF_MASK;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
return;
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV, current);
}
/*
* OK, we're invoking a handler
*/
static void
handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs)
{
struct k_sigaction *ka = &current->sighand->action[sig-1];
/* Are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
switch (regs->eax) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->eax = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->eax = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs);
else
setup_frame(sig, ka, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
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 fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
{
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->xcs & 2) != 2)
return 1;
if (current->flags & PF_FREEZE) {
refrigerator(0);
goto no_signal;
}
if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, 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.debugreg[7])
HYPERVISOR_set_debugreg(7,
current->thread.debugreg[7]);
/* Whee! Actually deliver the signal. */
handle_signal(signr, &info, oldset, regs);
return 1;
}
no_signal:
/* Did we come from a system call? */
if (regs->orig_eax >= 0) {
/* Restart the system call - no handlers present */
if (regs->eax == -ERESTARTNOHAND ||
regs->eax == -ERESTARTSYS ||
regs->eax == -ERESTARTNOINTR) {
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
if (regs->eax == -ERESTART_RESTARTBLOCK){
regs->eax = __NR_restart_syscall;
regs->eip -= 2;
}
}
return 0;
}
/*
* notification of userspace execution resumption
* - triggered by current->work.notify_resume
*/
__attribute__((regparm(3)))
void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
__u32 thread_info_flags)
{
/* 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);
clear_thread_flag(TIF_IRET);
}
@@ -0,0 +1,65 @@
/*
* linux/arch/i386/kernel/sysenter.c
*
* (C) Copyright 2002 Linus Torvalds
*
* This file contains the needed initializations to support sysenter.
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/thread_info.h>
#include <linux/sched.h>
#include <linux/gfp.h>
#include <linux/string.h>
#include <linux/elf.h>
#include <asm/cpufeature.h>
#include <asm/msr.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
extern asmlinkage void sysenter_entry(void);
void enable_sep_cpu(void *info)
{
int cpu = get_cpu();
struct tss_struct *tss = init_tss + cpu;
tss->ss1 = __KERNEL_CS;
tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
put_cpu();
}
/*
* These symbols are defined by vsyscall.o to mark the bounds
* of the ELF DSO images included therein.
*/
extern const char vsyscall_int80_start, vsyscall_int80_end;
extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
static int __init sysenter_setup(void)
{
unsigned long page = get_zeroed_page(GFP_ATOMIC);
__set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY);
if (1 /* XXXcl not yet */ || !boot_cpu_has(X86_FEATURE_SEP)) {
memcpy((void *) page,
&vsyscall_int80_start,
&vsyscall_int80_end - &vsyscall_int80_start);
return 0;
}
memcpy((void *) page,
&vsyscall_sysenter_start,
&vsyscall_sysenter_end - &vsyscall_sysenter_start);
on_each_cpu(enable_sep_cpu, NULL, 1, 1);
return 0;
}
__initcall(sysenter_setup);
@@ -0,0 +1,412 @@
/*
* 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 <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 */
#include "do_timer.h"
u64 jiffies_64 = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
unsigned long cpu_khz; /* Detected as we calibrate the TSC */
extern unsigned long wall_jiffies;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(i8253_lock);
struct timer_opts *cur_timer = &timer_none;
/*
* 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;
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 / 1000);
} while (read_seqretry(&xtime_lock, seq));
while (usec >= 1000000) {
usec -= 1000000;
sec++;
}
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, nsec = tv->tv_nsec;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
write_seqlock_irq(&xtime_lock);
/*
* 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 -= cur_timer->get_offset() * NSEC_PER_USEC;
nsec -= (jiffies - wall_jiffies) * TICK_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;
write_sequnlock_irq(&xtime_lock);
clock_was_set();
return 0;
}
EXPORT_SYMBOL(do_settimeofday);
#if 0
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;
}
/* last time the cmos clock got updated */
static long last_rtc_update;
#endif
int timer_ack;
/* 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);
/*
* 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)
{
#ifdef CONFIG_X86_IO_APIC
if (timer_ack) {
/*
* Subtle, when I/O APICs are used we have to ack timer IRQ
* manually to reset the IRR bit for do_slow_gettimeoffset().
* This will also deassert NMI lines for the watchdog if run
* on an 82489DX-based system.
*/
spin_lock(&i8259A_lock);
outb(0x0c, PIC_MASTER_OCW3);
/* Ack the IRQ; AEOI will end it automatically. */
inb(PIC_MASTER_POLL);
spin_unlock(&i8259A_lock);
}
#endif
do_timer_interrupt_hook(regs);
#if 0 /* XEN PRIV */
/*
* 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
#ifdef CONFIG_MCA
if( MCA_bus ) {
/* The PS/2 uses level-triggered interrupts. You can't
turn them off, nor would you want to (any attempt to
enable edge-triggered interrupts usually gets intercepted by a
special hardware circuit). Hence we have to acknowledge
the timer interrupt. Through some incredibly stupid
design idea, the reset for IRQ 0 is done by setting the
high bit of the PPI port B (0x61). Note that some PS/2s,
notably the 55SX, work fine if this is removed. */
irq = inb_p( 0x61 ); /* read the current state */
outb_p( irq|0x80, 0x61 ); /* reset the IRQ */
}
#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);
cur_timer->mark_offset();
if (regs) /* XXXcl check regs in do_timer_interrupt */
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;
static int time_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();
return 0;
}
static int time_resume(struct sys_device *dev)
{
unsigned long sec = get_cmos_time() + clock_cmos_diff;
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = sec;
xtime.tv_nsec = 0;
write_sequnlock_irq(&xtime_lock);
return 0;
}
static struct sysdev_class pit_sysclass = {
.resume = time_resume,
.suspend = time_suspend,
set_kset_name("pit"),
};
/* XXX this driverfs stuff should probably go elsewhere later -john */
static struct sys_device device_i8253 = {
.id = 0,
.cls = &pit_sysclass,
};
static int time_init_device(void)
{
int error = sysdev_class_register(&pit_sysclass);
if (!error)
error = sysdev_register(&device_i8253);
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();
wall_to_monotonic.tv_sec = -xtime.tv_sec;
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
wall_to_monotonic.tv_nsec = -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 time_irq;
static struct irqaction irq_timer = {
timer_interrupt, SA_INTERRUPT, 0, "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
xtime.tv_sec = HYPERVISOR_shared_info->wc_sec;
wall_to_monotonic.tv_sec = -xtime.tv_sec;
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
cur_timer = select_timer();
printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
time_irq = bind_virq_to_irq(VIRQ_TIMER);
(void)setup_irq(time_irq, &irq_timer);
}
@@ -0,0 +1,17 @@
#
# Makefile for x86 timers
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
obj-y := timer_tsc.o
c-obj-y := timer.o common.o timer_none.o timer_pit.o
c-link :=
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/i386/kernel/timers/$(notdir $@) $@
obj-y += $(c-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
@@ -0,0 +1,528 @@
/*
* This code largely moved from arch/i386/kernel/time.c.
* See comments there for proper credits.
*/
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/cpufreq.h>
#include <linux/string.h>
#include <linux/jiffies.h>
#include <asm/timer.h>
#include <asm/io.h>
/* processor.h for distable_tsc flag */
#include <asm/processor.h>
#include "io_ports.h"
#include "mach_timer.h"
#include <asm/hpet.h>
#ifdef CONFIG_HPET_TIMER
static unsigned long hpet_usec_quotient;
static unsigned long hpet_last;
struct timer_opts timer_tsc;
#endif
static inline void cpufreq_delayed_get(void);
int tsc_disable __initdata = 0;
extern spinlock_t i8253_lock;
static int use_tsc;
/* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt;
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
static unsigned long long monotonic_base;
static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
/* convert from cycles(64bits) => nanoseconds (64bits)
* basic equation:
* ns = cycles / (freq / ns_per_sec)
* ns = cycles * (ns_per_sec / freq)
* ns = cycles * (10^9 / (cpu_mhz * 10^6))
* ns = cycles * (10^3 / cpu_mhz)
*
* Then we use scaling math (suggested by george@mvista.com) to get:
* ns = cycles * (10^3 * SC / cpu_mhz) / SC
* ns = cycles * cyc2ns_scale / SC
*
* And since SC is a constant power of two, we can convert the div
* into a shift.
* -johnstul@us.ibm.com "math is hard, lets go shopping!"
*/
static unsigned long cyc2ns_scale;
#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
{
cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz;
}
static inline unsigned long long cycles_2_ns(unsigned long long cyc)
{
return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
}
#if 0
static int count2; /* counter for mark_offset_tsc() */
#endif
/* Cached *multiplier* to convert TSC counts to microseconds.
* (see the equation below).
* Equal to 2^32 * (1 / (clocks per usec) ).
* Initialized in time_init.
*/
static unsigned long fast_gettimeoffset_quotient;
/* These are peridically updated in shared_info, and then copied here. */
static u32 shadow_tsc_stamp;
static u64 shadow_system_time;
static u32 shadow_time_version;
static struct timeval shadow_tv;
/*
* 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)
{
do {
shadow_time_version = HYPERVISOR_shared_info->time_version2;
rmb();
shadow_tv.tv_sec = HYPERVISOR_shared_info->wc_sec;
shadow_tv.tv_usec = HYPERVISOR_shared_info->wc_usec;
shadow_tsc_stamp = HYPERVISOR_shared_info->tsc_timestamp.tsc_bits;
shadow_system_time = HYPERVISOR_shared_info->system_time;
rmb();
}
while (shadow_time_version != HYPERVISOR_shared_info->time_version1);
}
#define TIME_VALUES_UP_TO_DATE \
(shadow_time_version == HYPERVISOR_shared_info->time_version2)
static unsigned long get_offset_tsc(void)
{
register unsigned long eax, edx;
/* Read the Time Stamp Counter */
rdtsc(eax,edx);
/* .. relative to previous jiffy (32 bits is enough) */
eax -= last_tsc_low; /* tsc_low delta */
/*
* Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
* = (tsc_low delta) * (usecs_per_clock)
* = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
*
* Using a mull instead of a divl saves up to 31 clock cycles
* in the critical path.
*/
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
:"rm" (fast_gettimeoffset_quotient),
"0" (eax));
/* our adjusted time offset in microseconds */
return delay_at_last_interrupt + edx;
}
static unsigned long long monotonic_clock_tsc(void)
{
unsigned long long last_offset, this_offset, base;
unsigned seq;
/* atomically read monotonic base & last_offset */
do {
seq = read_seqbegin(&monotonic_lock);
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
base = monotonic_base;
} while (read_seqretry(&monotonic_lock, seq));
/* Read the Time Stamp Counter */
rdtscll(this_offset);
/* return the value in ns */
return base + cycles_2_ns(this_offset - last_offset);
}
/*
* Scheduler clock - returns current time in nanosec units.
*/
unsigned long long sched_clock(void)
{
unsigned long long this_offset;
/*
* In the NUMA case we dont use the TSC as they are not
* synchronized across all CPUs.
*/
#ifndef CONFIG_NUMA
if (!use_tsc)
#endif
/* no locking but a rare wrong value is not a big deal */
return jiffies_64 * (1000000000 / HZ);
/* Read the Time Stamp Counter */
rdtscll(this_offset);
/* return the value in ns */
return cycles_2_ns(this_offset);
}
static void mark_offset_tsc(void)
{
unsigned long lost,delay;
unsigned long delta = last_tsc_low;
#if 0
int count;
int countmp;
static int count1 = 0;
#endif
unsigned long long this_offset, last_offset;
static int lost_count = 0;
write_seqlock(&monotonic_lock);
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
/*
* It is important that these two operations happen almost at
* the same time. We do the RDTSC stuff first, since it's
* faster. To avoid any inconsistencies, we need interrupts
* disabled locally.
*/
/*
* Interrupts are just disabled locally since the timer irq
* has the SA_INTERRUPT flag set. -arca
*/
/* read Pentium cycle counter */
rdtsc(last_tsc_low, last_tsc_high);
#if 0
spin_lock(&i8253_lock);
outb_p(0x00, PIT_MODE); /* latch the count ASAP */
count = inb_p(PIT_CH0); /* read the latched count */
count |= inb(PIT_CH0) << 8;
/*
* VIA686a test code... reset the latch if count > max + 1
* from timer_pit.c - cjb
*/
if (count > LATCH) {
outb_p(0x34, PIT_MODE);
outb_p(LATCH & 0xff, PIT_CH0);
outb(LATCH >> 8, PIT_CH0);
count = LATCH - 1;
}
spin_unlock(&i8253_lock);
if (pit_latch_buggy) {
/* get center value of last 3 time lutch */
if ((count2 >= count && count >= count1)
|| (count1 >= count && count >= count2)) {
count2 = count1; count1 = count;
} else if ((count1 >= count2 && count2 >= count)
|| (count >= count2 && count2 >= count1)) {
countmp = count;count = count2;
count2 = count1;count1 = countmp;
} else {
count2 = count1; count1 = count; count = count1;
}
}
#endif
/* lost tick compensation */
delta = last_tsc_low - delta;
{
register unsigned long eax, edx;
eax = delta;
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
:"rm" (fast_gettimeoffset_quotient),
"0" (eax));
delta = edx;
}
delta += delay_at_last_interrupt;
lost = delta/(1000000/HZ);
delay = delta%(1000000/HZ);
if (lost >= 2) {
jiffies_64 += lost-1;
/* sanity check to ensure we're not always losing ticks */
if (lost_count++ > 100) {
printk(KERN_WARNING "Losing too many ticks!\n");
printk(KERN_WARNING "TSC cannot be used as a timesource. \n");
printk(KERN_WARNING "Possible reasons for this are:\n");
printk(KERN_WARNING " You're running with Speedstep,\n");
printk(KERN_WARNING " You don't have DMA enabled for your hard disk (see hdparm),\n");
printk(KERN_WARNING " Incorrect TSC synchronization on an SMP system (see dmesg).\n");
printk(KERN_WARNING "Falling back to a sane timesource now.\n");
clock_fallback();
}
/* ... but give the TSC a fair chance */
if (lost_count > 25)
cpufreq_delayed_get();
} else
lost_count = 0;
/* update the monotonic base value */
this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
monotonic_base += cycles_2_ns(this_offset - last_offset);
write_sequnlock(&monotonic_lock);
#if 0
/* calculate delay_at_last_interrupt */
count = ((LATCH-1) - count) * TICK_SIZE;
delay_at_last_interrupt = (count + LATCH/2) / LATCH;
#else
delay_at_last_interrupt = 0;
#endif
/* catch corner case where tick rollover occured
* between tsc and pit reads (as noted when
* usec delta is > 90% # of usecs/tick)
*/
if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
jiffies_64++;
}
static void delay_tsc(unsigned long loops)
{
unsigned long bclock, now;
rdtscl(bclock);
do
{
rep_nop();
rdtscl(now);
} while ((now-bclock) < loops);
}
#ifdef CONFIG_HPET_TIMER
static void mark_offset_tsc_hpet(void)
{
unsigned long long this_offset, last_offset;
unsigned long offset, temp, hpet_current;
write_seqlock(&monotonic_lock);
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
/*
* It is important that these two operations happen almost at
* the same time. We do the RDTSC stuff first, since it's
* faster. To avoid any inconsistencies, we need interrupts
* disabled locally.
*/
/*
* Interrupts are just disabled locally since the timer irq
* has the SA_INTERRUPT flag set. -arca
*/
/* read Pentium cycle counter */
hpet_current = hpet_readl(HPET_COUNTER);
rdtsc(last_tsc_low, last_tsc_high);
/* lost tick compensation */
offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))) {
int lost_ticks = (offset - hpet_last) / hpet_tick;
jiffies_64 += lost_ticks;
}
hpet_last = hpet_current;
/* update the monotonic base value */
this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
monotonic_base += cycles_2_ns(this_offset - last_offset);
write_sequnlock(&monotonic_lock);
/* calculate delay_at_last_interrupt */
/*
* Time offset = (hpet delta) * ( usecs per HPET clock )
* = (hpet delta) * ( usecs per tick / HPET clocks per tick)
* = (hpet delta) * ( hpet_usec_quotient ) / (2^32)
* Where,
* hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick
*/
delay_at_last_interrupt = hpet_current - offset;
ASM_MUL64_REG(temp, delay_at_last_interrupt,
hpet_usec_quotient, delay_at_last_interrupt);
}
#endif
#ifdef CONFIG_CPU_FREQ
#include <linux/workqueue.h>
static unsigned int cpufreq_delayed_issched = 0;
static unsigned int cpufreq_init = 0;
static struct work_struct cpufreq_delayed_get_work;
static void handle_cpufreq_delayed_get(void *v)
{
unsigned int cpu;
for_each_online_cpu(cpu) {
cpufreq_get(cpu);
}
cpufreq_delayed_issched = 0;
}
/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
* to verify the CPU frequency the timing core thinks the CPU is running
* at is still correct.
*/
static inline void cpufreq_delayed_get(void)
{
if (cpufreq_init && !cpufreq_delayed_issched) {
cpufreq_delayed_issched = 1;
printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");
schedule_work(&cpufreq_delayed_get_work);
}
}
/* If the CPU frequency is scaled, TSC-based delays will need a different
* loops_per_jiffy value to function properly.
*/
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
#ifndef CONFIG_SMP
static unsigned long fast_gettimeoffset_ref = 0;
static unsigned long cpu_khz_ref = 0;
#endif
static int
time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
write_seqlock_irq(&xtime_lock);
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
#ifndef CONFIG_SMP
fast_gettimeoffset_ref = fast_gettimeoffset_quotient;
cpu_khz_ref = cpu_khz;
#endif
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
(val == CPUFREQ_RESUMECHANGE)) {
if (!(freq->flags & CPUFREQ_CONST_LOOPS))
cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
#ifndef CONFIG_SMP
if (cpu_khz)
cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
if (use_tsc) {
if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
set_cyc2ns_scale(cpu_khz/1000);
}
}
#endif
}
write_sequnlock_irq(&xtime_lock);
return 0;
}
static struct notifier_block time_cpufreq_notifier_block = {
.notifier_call = time_cpufreq_notifier
};
static int __init cpufreq_tsc(void)
{
int ret;
INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
if (!ret)
cpufreq_init = 1;
return ret;
}
core_initcall(cpufreq_tsc);
#else /* CONFIG_CPU_FREQ */
static inline void cpufreq_delayed_get(void) { return; }
#endif
static int __init init_tsc(char* override)
{
unsigned long long alarm;
u64 __cpu_khz;
__cpu_khz = HYPERVISOR_shared_info->cpu_freq;
do_div(__cpu_khz, 1000);
cpu_khz = (u32)__cpu_khz;
printk(KERN_INFO "Xen reported: %lu.%03lu MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
/* (10^6 * 2^32) / cpu_khz = (2^32 * 1 / (clocks/us)) */
{
unsigned long eax=0, edx=1000;
__asm__("divl %2"
:"=a" (fast_gettimeoffset_quotient), "=d" (edx)
:"r" (cpu_khz),
"0" (eax), "1" (edx));
}
set_cyc2ns_scale(cpu_khz/1000);
__get_time_values_from_xen();
rdtscll(alarm);
return 0;
}
#ifndef CONFIG_X86_TSC
/* disable flag for tsc. Takes effect by clearing the TSC cpu flag
* in cpu/common.c */
static int __init tsc_setup(char *str)
{
tsc_disable = 1;
return 1;
}
#else
static int __init tsc_setup(char *str)
{
printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
"cannot disable TSC.\n");
return 1;
}
#endif
__setup("notsc", tsc_setup);
/************************************************************/
/* tsc timer_opts struct */
struct timer_opts timer_tsc = {
.name = "tsc",
.init = init_tsc,
.mark_offset = mark_offset_tsc,
.get_offset = get_offset_tsc,
.monotonic_clock = monotonic_clock_tsc,
.delay = delay_tsc,
};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,135 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(startup_32)
jiffies = jiffies_64;
SECTIONS
{
. = 0xC0000000 + 0x100000;
/* read-only */
_text = .; /* Text and read-only data */
.text : {
*(.text)
SCHED_TEXT
*(.fixup)
*(.gnu.warning)
} = 0x9090
_etext = .; /* End of text section */
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
RODATA
/* writeable */
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
. = ALIGN(4096);
__nosave_begin = .;
.data_nosave : { *(.data.nosave) }
. = ALIGN(4096);
__nosave_end = .;
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
_edata = .; /* End of data section */
. = ALIGN(THREAD_SIZE); /* init_task */
.data.init_task : { *(.data.init_task) }
/* will be freed after init */
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.init.text : {
_sinittext = .;
*(.init.text)
_einittext = .;
}
.init.data : { *(.init.data) }
. = ALIGN(16);
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
__start___param = .;
__param : { *(__param) }
__stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
__con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .;
SECURITY_INIT
. = ALIGN(4);
__alt_instructions = .;
.altinstructions : { *(.altinstructions) }
__alt_instructions_end = .;
.altinstr_replacement : { *(.altinstr_replacement) }
/* .exit.text is discard at runtime, not link time, to deal with references
from .altinstructions and .eh_frame */
.exit.text : { *(.exit.text) }
.exit.data : { *(.exit.data) }
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(32);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
__bss_start = .; /* BSS */
.bss : {
*(.bss.page_aligned)
*(.bss)
}
. = ALIGN(4);
__bss_stop = .;
_end = . ;
/* This is where the kernel creates the early boot page tables */
. = ALIGN(4096);
pg0 = .;
/* Sections to be discarded */
/DISCARD/ : {
*(.exitcall.exit)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
@@ -0,0 +1,15 @@
#include <linux/init.h>
__INITDATA
.globl vsyscall_int80_start, vsyscall_int80_end
vsyscall_int80_start:
.incbin "arch/xen/i386/kernel/vsyscall-int80.so"
vsyscall_int80_end:
.globl vsyscall_sysenter_start, vsyscall_sysenter_end
vsyscall_sysenter_start:
.incbin "arch/xen/i386/kernel/vsyscall-sysenter.so"
vsyscall_sysenter_end:
__FINIT
@@ -0,0 +1,69 @@
/*
* Linker script for vsyscall DSO. The vsyscall page is an ELF shared
* object prelinked to its virtual address, and with only one read-only
* segment (that fits in one page). This script controls its layout.
*/
/* This must match <asm/fixmap.h>. */
/* = FIXADDR_TOP - PAGE_SIZE
= HYPERVISOR_VIRT_START - 2 * PAGE_SIZE - PAGE_SIZE */
VSYSCALL_BASE = 0xfbffd000;
SECTIONS
{
. = VSYSCALL_BASE + SIZEOF_HEADERS;
.hash : { *(.hash) } :text
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
/* This linker script is used both with -r and with -shared.
For the layouts to match, we need to skip more than enough
space for the dynamic symbol table et al. If this amount
is insufficient, ld -shared will barf. Just increase it here. */
. = VSYSCALL_BASE + 0x400;
.text : { *(.text) } :text =0x90909090
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
.eh_frame : { KEEP (*(.eh_frame)) } :text
.dynamic : { *(.dynamic) } :text :dynamic
.useless : {
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
} :text
}
/*
* We must supply the ELF program headers explicitly to get just one
* PT_LOAD segment, and set the flags explicitly to make segments read-only.
*/
PHDRS
{
text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
}
/*
* This controls what symbols we export from the DSO.
*/
VERSION
{
LINUX_2.5 {
global:
__kernel_vsyscall;
__kernel_sigreturn;
__kernel_rt_sigreturn;
local: *;
};
}
/* The ELF entry point can be used to set the AT_SYSINFO value. */
ENTRY(__kernel_vsyscall);
@@ -0,0 +1,24 @@
#
# Makefile for the linux i386-specific parts of the memory manager.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
CFLAGS += -Iarch/$(XENARCH)/mm
obj-y := init.o fault.o pgtable.o hypervisor.o
c-obj-y := ioremap.o extable.o pageattr.o
c-obj-$(CONFIG_DISCONTIGMEM) += discontig.o
c-obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
c-obj-$(CONFIG_HIGHMEM) += highmem.o
c-obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o
c-link :=
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)):
@ln -fsn $(srctree)/arch/i386/mm/$(notdir $@) $@
obj-y += $(c-obj-y)
clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
@@ -0,0 +1,517 @@
/*
* linux/arch/i386/mm/fault.c
*
* Copyright (C) 1995 Linus Torvalds
*/
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/hardirq.h>
#include <asm/desc.h>
extern void die(const char *,struct pt_regs *,long);
pgd_t *cur_pgd; /* XXXsmp */
/*
* Unlock any spinlocks which will prevent us from getting the
* message out
*/
void bust_spinlocks(int yes)
{
int loglevel_save = console_loglevel;
if (yes) {
oops_in_progress = 1;
return;
}
#ifdef CONFIG_VT
unblank_screen();
#endif
oops_in_progress = 0;
/*
* OK, the message is on the console. Now we call printk()
* without oops_in_progress set so that printk will give klogd
* a poke. Hold onto your hats...
*/
console_loglevel = 15; /* NMI oopser may have shut the console up */
printk(" ");
console_loglevel = loglevel_save;
}
/*
* Return EIP plus the CS segment base. The segment limit is also
* adjusted, clamped to the kernel/user address space (whichever is
* appropriate), and returned in *eip_limit.
*
* The segment is checked, because it might have been changed by another
* task between the original faulting instruction and here.
*
* If CS is no longer a valid code segment, or if EIP is beyond the
* limit, or if it is a kernel address when CS is not a kernel segment,
* then the returned value will be greater than *eip_limit.
*
* This is slow, but is very rarely executed.
*/
static inline unsigned long get_segment_eip(struct pt_regs *regs,
unsigned long *eip_limit)
{
unsigned long eip = regs->eip;
unsigned seg = regs->xcs & 0xffff;
u32 seg_ar, seg_limit, base, *desc;
/* The standard kernel/user address space limit. */
*eip_limit = (seg & 2) ? USER_DS.seg : KERNEL_DS.seg;
/* Unlikely, but must come before segment checks. */
if (unlikely((regs->eflags & VM_MASK) != 0))
return eip + (seg << 4);
/* By far the most common cases. */
if (likely(seg == __USER_CS || seg == __KERNEL_CS))
return eip;
/* Check the segment exists, is within the current LDT/GDT size,
that kernel/user (ring 0..3) has the appropriate privilege,
that it's a code segment, and get the limit. */
__asm__ ("larl %3,%0; lsll %3,%1"
: "=&r" (seg_ar), "=r" (seg_limit) : "0" (0), "rm" (seg));
if ((~seg_ar & 0x9800) || eip > seg_limit) {
*eip_limit = 0;
return 1; /* So that returned eip > *eip_limit. */
}
/* Get the GDT/LDT descriptor base.
When you look for races in this code remember that
LDT and other horrors are only used in user space. */
if (seg & (1<<2)) {
/* Must lock the LDT while reading it. */
down(&current->mm->context.sem);
desc = current->mm->context.ldt;
desc = (void *)desc + (seg & ~7);
} else {
/* Must disable preemption while reading the GDT. */
desc = (u32 *)get_cpu_gdt_table(get_cpu());
desc = (void *)desc + (seg & ~7);
}
/* Decode the code segment base from the descriptor */
base = (desc[0] >> 16) |
((desc[1] & 0xff) << 16) |
(desc[1] & 0xff000000);
if (seg & (1<<2)) {
up(&current->mm->context.sem);
} else
put_cpu();
/* Adjust EIP and segment limit, and clamp at the kernel limit.
It's legitimate for segments to wrap at 0xffffffff. */
seg_limit += base;
if (seg_limit < *eip_limit && seg_limit >= base)
*eip_limit = seg_limit;
return eip + base;
}
/*
* Sometimes AMD Athlon/Opteron CPUs report invalid exceptions on prefetch.
* Check that here and ignore it.
*/
static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
{
unsigned long limit;
unsigned long instr = get_segment_eip (regs, &limit);
int scan_more = 1;
int prefetch = 0;
int i;
for (i = 0; scan_more && i < 15; i++) {
unsigned char opcode;
unsigned char instr_hi;
unsigned char instr_lo;
if (instr > limit)
break;
if (__get_user(opcode, (unsigned char *) instr))
break;
instr_hi = opcode & 0xf0;
instr_lo = opcode & 0x0f;
instr++;
switch (instr_hi) {
case 0x20:
case 0x30:
/* Values 0x26,0x2E,0x36,0x3E are valid x86 prefixes. */
scan_more = ((instr_lo & 7) == 0x6);
break;
case 0x60:
/* 0x64 thru 0x67 are valid prefixes in all modes. */
scan_more = (instr_lo & 0xC) == 0x4;
break;
case 0xF0:
/* 0xF0, 0xF2, and 0xF3 are valid prefixes */
scan_more = !instr_lo || (instr_lo>>1) == 1;
break;
case 0x00:
/* Prefetch instruction is 0x0F0D or 0x0F18 */
scan_more = 0;
if (instr > limit)
break;
if (__get_user(opcode, (unsigned char *) instr))
break;
prefetch = (instr_lo == 0xF) &&
(opcode == 0x0D || opcode == 0x18);
break;
default:
scan_more = 0;
break;
}
}
return prefetch;
}
static inline int is_prefetch(struct pt_regs *regs, unsigned long addr)
{
if (unlikely(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
boot_cpu_data.x86 >= 6))
return __is_prefetch(regs, addr);
return 0;
}
asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
/*
* 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
*/
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;
unsigned long page;
int write;
siginfo_t info;
/* Set the "privileged fault" bit to something sane. */
error_code &= 3;
error_code |= (regs->xcs & 2) << 1;
#if 0
/* It's safe to allow irq's after cr2 has been saved */
if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
local_irq_enable();
#endif
tsk = current;
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))
goto vmalloc_fault;
/*
* Don't take the mm semaphore here. If we fixup a prefetch
* fault we could otherwise deadlock.
*/
goto bad_area_nosemaphore;
}
mm = tsk->mm;
/*
* If we're in an interrupt, have no user context or are running in an
* atomic region then we must not take the fault..
*/
if (in_atomic() || !mm)
goto bad_area_nosemaphore;
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
if (error_code & 4) {
/*
* accessing the stack below %esp is always a bug.
* The "+ 32" is there due to some instructions (like
* pusha) doing post-decrement on the stack and that
* doesn't show up until later..
*/
if (address + 32 < regs->esp)
goto bad_area;
}
if (expand_stack(vma, address))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
info.si_code = SEGV_ACCERR;
write = 0;
switch (error_code & 3) {
default: /* 3: write, present */
#ifdef TEST_VERIFY_AREA
if (regs->cs == KERNEL_CS)
printk("WP fault at %08lx\n", regs->eip);
#endif
/* fall through */
case 2: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
write++;
break;
case 1: /* read, present */
goto bad_area;
case 0: /* read, not present */
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
survive:
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
switch (handle_mm_fault(mm, vma, address, write)) {
case VM_FAULT_MINOR:
tsk->min_flt++;
break;
case VM_FAULT_MAJOR:
tsk->maj_flt++;
break;
case VM_FAULT_SIGBUS:
goto do_sigbus;
case VM_FAULT_OOM:
goto out_of_memory;
default:
BUG();
}
/*
* Did it hit the DOS screen memory VA from vm86 mode?
*/
if (regs->eflags & VM_MASK) {
unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
if (bit < 32)
tsk->thread.screen_bitmap |= 1 << bit;
}
up_read(&mm->mmap_sem);
return;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
up_read(&mm->mmap_sem);
bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
/*
* Valid to do another page fault here because this one came
* from user space.
*/
if (is_prefetch(regs, address))
return;
tsk->thread.cr2 = address;
/* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14;
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code has been set above */
info.si_addr = (void *)address;
force_sig_info(SIGSEGV, &info, tsk);
return;
}
#ifdef CONFIG_X86_F00F_BUG
/*
* Pentium F0 0F C7 C8 bug workaround.
*/
if (boot_cpu_data.f00f_bug) {
unsigned long nr;
nr = (address - idt_descr.address) >> 3;
if (nr == 6) {
do_invalid_op(regs, 0);
return;
}
}
#endif
no_context:
/* Are we prepared to handle this kernel fault? */
if (fixup_exception(regs))
return;
/*
* Valid to do another page fault here, because if this fault
* had been triggered by is_prefetch fixup_exception would have
* handled it.
*/
if (is_prefetch(regs, address))
return;
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
bust_spinlocks(1);
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 virtual address %08lx\n",address);
printk(KERN_ALERT " printing eip:\n");
printk("%08lx\n", regs->eip);
page = ((unsigned long *) cur_pgd)[address >> 22];
printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page, machine_to_phys(page));
/*
* We must not directly access the pte in the highpte
* case, the page table might be allocated in highmem.
* And lets rather not kmap-atomic the pte, just in case
* it's allocated already.
*/
#ifndef CONFIG_HIGHPTE
if (page & 1) {
page &= PAGE_MASK;
address &= 0x003ff000;
page = machine_to_phys(page);
page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
printk(KERN_ALERT "*pte = ma %08lx pa %08lx\n", page, machine_to_phys(page));
}
#endif
show_trace(NULL, (unsigned long *)&regs[1]);
die("Oops", regs, error_code);
bust_spinlocks(0);
do_exit(SIGKILL);
/*
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.
*/
out_of_memory:
up_read(&mm->mmap_sem);
if (tsk->pid == 1) {
yield();
down_read(&mm->mmap_sem);
goto survive;
}
printk("VM: killing process %s\n", tsk->comm);
if (error_code & 4)
do_exit(SIGKILL);
goto no_context;
do_sigbus:
up_read(&mm->mmap_sem);
/* Kernel mode? Handle exceptions or die */
if (!(error_code & 4))
goto no_context;
/* User space => ok to do another page fault */
if (is_prefetch(regs, address))
return;
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 *)address;
force_sig_info(SIGBUS, &info, tsk);
return;
vmalloc_fault:
{
/*
* Synchronize this task's top level page-table
* with the 'reference' page table.
*
* Do _not_ use "tsk" here. We might be inside
* an interrupt in the middle of a task switch..
*/
int index = pgd_index(address);
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
pte_t *pte_k;
pgd = index + cur_pgd;
pgd_k = init_mm.pgd + index;
if (!pgd_present(*pgd_k))
goto no_context;
/*
* set_pgd(pgd, *pgd_k); here would be useless on PAE
* and redundant with the set_pmd() on non-PAE.
*/
pmd = pmd_offset(pgd, address);
pmd_k = pmd_offset(pgd_k, address);
if (!pmd_present(*pmd_k))
goto no_context;
set_pmd(pmd, *pmd_k);
xen_flush_page_update_queue(); /* flush PMD update */
pte_k = pte_offset_kernel(pmd_k, address);
if (!pte_present(*pte_k))
goto no_context;
return;
}
}
@@ -0,0 +1,264 @@
/******************************************************************************
* xen/i386/mm/hypervisor.c
*
* Update page tables via the hypervisor.
*
* Copyright (c) 2002, K A Fraser
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <asm/hypervisor.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm-xen/multicall.h>
/*
* 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;
#if 0
#define QUEUE_SIZE 2048
#else
#define QUEUE_SIZE 1
#endif
static mmu_update_t update_queue[QUEUE_SIZE];
unsigned int mmu_update_queue_idx = 0;
#define idx mmu_update_queue_idx
#if MMU_UPDATE_DEBUG > 0
page_update_debug_t update_debug_queue[QUEUE_SIZE] = {{0}};
#undef queue_l1_entry_update
#undef queue_l2_entry_update
#endif
#if MMU_UPDATE_DEBUG > 3
static void DEBUG_allow_pt_reads(void)
{
pte_t *pte;
mmu_update_t update;
int i;
for ( i = idx-1; i >= 0; i-- )
{
pte = update_debug_queue[i].ptep;
if ( pte == NULL ) continue;
update_debug_queue[i].ptep = NULL;
update.ptr = virt_to_machine(pte);
update.val = update_debug_queue[i].pteval;
HYPERVISOR_mmu_update(&update, 1, NULL);
}
}
static void DEBUG_disallow_pt_read(unsigned long va)
{
pte_t *pte;
pmd_t *pmd;
pgd_t *pgd;
unsigned long pteval;
/*
* We may fault because of an already outstanding update.
* That's okay -- it'll get fixed up in the fault handler.
*/
mmu_update_t update;
pgd = pgd_offset_k(va);
pmd = pmd_offset(pgd, va);
pte = pte_offset_kernel(pmd, va); /* XXXcl */
update.ptr = virt_to_machine(pte);
pteval = *(unsigned long *)pte;
update.val = pteval & ~_PAGE_PRESENT;
HYPERVISOR_mmu_update(&update, 1, NULL);
update_debug_queue[idx].ptep = pte;
update_debug_queue[idx].pteval = pteval;
}
#endif
#if MMU_UPDATE_DEBUG > 1
#undef queue_pt_switch
#undef queue_tlb_flush
#undef queue_invlpg
#undef queue_pgd_pin
#undef queue_pgd_unpin
#undef queue_pte_pin
#undef queue_pte_unpin
#undef queue_set_ldt
#endif
/*
* 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)
{
unsigned long flags;
unsigned int _idx;
spin_lock_irqsave(&update_lock, flags);
if ( (_idx = idx) != 0 )
{
#if MMU_UPDATE_DEBUG > 1
if (idx > 1)
printk("Flushing %d entries from pt update queue\n", idx);
#endif
#if MMU_UPDATE_DEBUG > 3
DEBUG_allow_pt_reads();
#endif
idx = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
queue_multicall3(__HYPERVISOR_mmu_update,
(unsigned long)update_queue,
(unsigned long)_idx,
(unsigned long)NULL);
}
spin_unlock_irqrestore(&update_lock, flags);
}
static inline void __flush_page_update_queue(void)
{
unsigned int _idx = idx;
#if MMU_UPDATE_DEBUG > 1
if (idx > 1)
printk("Flushing %d entries from pt update queue\n", idx);
#endif
#if MMU_UPDATE_DEBUG > 3
DEBUG_allow_pt_reads();
#endif
idx = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
if (unlikely(HYPERVISOR_mmu_update(update_queue, _idx, NULL) < 0))
panic("Failed to execute MMU updates");
}
void _flush_page_update_queue(void)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
if ( idx != 0 ) __flush_page_update_queue();
spin_unlock_irqrestore(&update_lock, flags);
}
static inline void increment_index(void)
{
idx++;
if ( unlikely(idx == QUEUE_SIZE) ) __flush_page_update_queue();
}
void queue_l1_entry_update(pte_t *ptr, unsigned long val)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
#if MMU_UPDATE_DEBUG > 3
DEBUG_disallow_pt_read((unsigned long)ptr);
#endif
update_queue[idx].ptr = virt_to_machine(ptr);
update_queue[idx].val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_l2_entry_update(pmd_t *ptr, unsigned long val)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = virt_to_machine(ptr);
update_queue[idx].val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pt_switch(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = phys_to_machine(ptr);
update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_NEW_BASEPTR;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_tlb_flush(void)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_TLB_FLUSH;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_invlpg(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
update_queue[idx].ptr |= ptr & PAGE_MASK;
update_queue[idx].val = MMUEXT_INVLPG;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_pin(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = phys_to_machine(ptr);
update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_PIN_L2_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_unpin(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = phys_to_machine(ptr);
update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_pin(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = phys_to_machine(ptr);
update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_PIN_L1_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_unpin(unsigned long ptr)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = phys_to_machine(ptr);
update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
update_queue[idx].val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_set_ldt(unsigned long ptr, unsigned long len)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = MMU_EXTENDED_COMMAND | ptr;
update_queue[idx].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)
{
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
update_queue[idx].val = pfn;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
@@ -0,0 +1,702 @@
/*
* linux/arch/i386/mm/init.c
*
* Copyright (C) 1995 Linus Torvalds
*
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/efi.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/tlbflush.h>
#include <asm/sections.h>
#include <asm/hypervisor.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
unsigned long highstart_pfn, highend_pfn;
static int do_test_wp_bit(void);
/*
* Creates a middle page table and puts a pointer to it in the
* given global directory entry. This only returns the gd entry
* in non-PAE compilation mode, since the middle layer is folded.
*/
static pmd_t * __init one_md_table_init(pgd_t *pgd)
{
pmd_t *pmd_table;
#ifdef CONFIG_X86_PAE
pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
if (pmd_table != pmd_offset(pgd, 0))
BUG();
#else
pmd_table = pmd_offset(pgd, 0);
#endif
return pmd_table;
}
/*
* Create a page table and place a pointer to it in a middle page
* directory entry.
*/
static pte_t * __init one_page_table_init(pmd_t *pmd)
{
if (pmd_none(*pmd)) {
pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
flush_page_update_queue();
if (page_table != pte_offset_kernel(pmd, 0))
BUG();
wrprotect_bootpt((pgd_t *)start_info.pt_base, page_table, 1);
return page_table;
}
return pte_offset_kernel(pmd, 0);
}
/*
* This function initializes a certain range of kernel virtual memory
* with new bootmem page tables, everywhere page tables are missing in
* the given range.
*/
/*
* NOTE: The pagetables are allocated contiguous on the physical space
* so we can cache the place of the first one and move around without
* checking the pgd every time.
*/
static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
{
pgd_t *pgd;
pmd_t *pmd;
int pgd_idx, pmd_idx;
unsigned long vaddr;
vaddr = start;
pgd_idx = pgd_index(vaddr);
pmd_idx = pmd_index(vaddr);
pgd = pgd_base + pgd_idx;
for ( ; (pgd_idx < PTRS_PER_PGD_NO_HV) && (vaddr != end); pgd++, pgd_idx++) {
if (pgd_none(*pgd))
one_md_table_init(pgd);
pmd = pmd_offset(pgd, vaddr);
for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
if (pmd_none(*pmd))
one_page_table_init(pmd);
vaddr += PMD_SIZE;
}
pmd_idx = 0;
}
}
void __init wrprotect_bootpt(pgd_t *pgd, void *page, int set)
{
pmd_t *pmd;
pte_t *pte;
unsigned long addr;
addr = (unsigned long)page;
pgd += pgd_index(addr);
pmd = pmd_offset(pgd, addr);
pte = pte_offset_kernel(pmd, addr);
if (!pte_present(*pte))
return;
queue_l1_entry_update(pte, set ? pte_val_ma(*pte) & ~_PAGE_RW :
pte_val_ma(*pte) | _PAGE_RW);
}
static void __init protect_bootpt_entries(pgd_t *spgd, pgd_t *dpgd, int set,
int pmdupdate, int pmdset)
{
pmd_t *pmd;
pte_t *pte;
int pgd_idx, pmd_idx;
for (pgd_idx = 0; pgd_idx < PTRS_PER_PGD_NO_HV; spgd++, pgd_idx++) {
pmd = pmd_offset(spgd, 0);
if (pmd_none(*pmd))
continue;
if (pmdupdate)
wrprotect_bootpt(dpgd, pmd, pmdset);
for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD; pmd++, pmd_idx++) {
if (cpu_has_pse) {
/* XXX */
} else {
pte = pte_offset_kernel(pmd, 0);
wrprotect_bootpt(dpgd, pte, set);
}
}
}
flush_page_update_queue();
}
/*
* This maps the physical memory to kernel virtual address space, a total
* of max_low_pfn pages, by creating page tables starting from address
* PAGE_OFFSET.
*/
static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
{
unsigned long pfn;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
int pgd_idx, pmd_idx, pte_ofs;
pgd_idx = pgd_index(PAGE_OFFSET);
pgd = pgd_base + pgd_idx;
pfn = 0;
pmd_idx = pmd_index(PAGE_OFFSET);
pte_ofs = pte_index(PAGE_OFFSET);
for (; pgd_idx < PTRS_PER_PGD_NO_HV; pgd++, pgd_idx++) {
pmd = one_md_table_init(pgd);
if (pfn >= max_low_pfn)
continue;
pmd += pmd_idx;
for (; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
/* Map with big pages if possible, otherwise create normal page tables. */
if (cpu_has_pse) {
set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
pfn += PTRS_PER_PTE;
} else {
pte = one_page_table_init(pmd);
pte += pte_ofs;
for (; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++)
set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
pte_ofs = 0;
}
flush_page_update_queue();
}
pmd_idx = 0;
}
}
static inline int page_kills_ppro(unsigned long pagenr)
{
if (pagenr >= 0x70000 && pagenr <= 0x7003F)
return 1;
return 0;
}
extern int is_available_memory(efi_memory_desc_t *);
static inline int page_is_ram(unsigned long pagenr)
{
int i;
unsigned long addr, end;
if (efi_enabled) {
efi_memory_desc_t *md;
for (i = 0; i < memmap.nr_map; i++) {
md = &memmap.map[i];
if (!is_available_memory(md))
continue;
addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
if ((pagenr >= addr) && (pagenr < end))
return 1;
}
return 0;
}
for (i = 0; i < e820.nr_map; i++) {
if (e820.map[i].type != E820_RAM) /* not usable memory */
continue;
/*
* !!!FIXME!!! Some BIOSen report areas as RAM that
* are not. Notably the 640->1Mb area. We need a sanity
* check here.
*/
addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
if ((pagenr >= addr) && (pagenr < end))
return 1;
}
return 0;
}
#ifdef CONFIG_HIGHMEM
pte_t *kmap_pte;
pgprot_t kmap_prot;
EXPORT_SYMBOL(kmap_prot);
EXPORT_SYMBOL(kmap_pte);
#define kmap_get_fixmap_pte(vaddr) \
pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
void __init kmap_init(void)
{
unsigned long kmap_vstart;
/* cache the first kmap pte */
kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
kmap_prot = PAGE_KERNEL;
}
void __init permanent_kmaps_init(pgd_t *pgd_base)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
unsigned long vaddr;
vaddr = PKMAP_BASE;
page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
pgd = swapper_pg_dir + pgd_index(vaddr);
pmd = pmd_offset(pgd, vaddr);
pte = pte_offset_kernel(pmd, vaddr);
pkmap_page_table = pte;
}
void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
{
if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
ClearPageReserved(page);
set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
totalhigh_pages++;
} else
SetPageReserved(page);
}
#ifndef CONFIG_DISCONTIGMEM
void __init set_highmem_pages_init(int bad_ppro)
{
int pfn;
for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
totalram_pages += totalhigh_pages;
}
#else
extern void set_highmem_pages_init(int);
#endif /* !CONFIG_DISCONTIGMEM */
#else
#define kmap_init() do { } while (0)
#define permanent_kmaps_init(pgd_base) do { } while (0)
#define set_highmem_pages_init(bad_ppro) do { } while (0)
#endif /* CONFIG_HIGHMEM */
unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
#ifndef CONFIG_DISCONTIGMEM
#define remap_numa_kva() do {} while (0)
#else
extern void __init remap_numa_kva(void);
#endif
static void __init pagetable_init (void)
{
unsigned long vaddr;
pgd_t *pgd_base = swapper_pg_dir;
#ifdef CONFIG_X86_PAE
int i;
/* Init entries of the first-level page table to the zero page */
for (i = 0; i < PTRS_PER_PGD; i++)
set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
#endif
/* Enable PSE if available */
if (cpu_has_pse) {
set_in_cr4(X86_CR4_PSE);
}
/* Enable PGE if available */
if (cpu_has_pge) {
set_in_cr4(X86_CR4_PGE);
__PAGE_KERNEL |= _PAGE_GLOBAL;
}
kernel_physical_mapping_init(pgd_base);
remap_numa_kva();
/*
* Fixed mappings, only the page table structure has to be
* created - mappings will be set by set_fixmap():
*/
vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
page_table_range_init(vaddr, 0, pgd_base);
permanent_kmaps_init(pgd_base);
#ifdef CONFIG_X86_PAE
/*
* Add low memory identity-mappings - SMP needs it when
* starting up on an AP from real-mode. In the non-PAE
* case we already have these mappings through head.S.
* All user-space mappings are explicitly cleared after
* SMP startup.
*/
pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
#endif
}
#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
/*
* Swap suspend & friends need this for resume because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
*/
char __nosavedata swsusp_pg_dir[PAGE_SIZE]
__attribute__ ((aligned (PAGE_SIZE)));
static inline void save_pg_dir(void)
{
memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
}
#else
static inline void save_pg_dir(void)
{
}
#endif
void zap_low_mappings (void)
{
int i;
save_pg_dir();
/*
* Zap initial low-memory mappings.
*
* Note that "pgd_clear()" doesn't do it for
* us, because pgd_clear() is a no-op on i386.
*/
for (i = 0; i < USER_PTRS_PER_PGD; i++)
#ifdef CONFIG_X86_PAE
set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
#else
set_pgd(swapper_pg_dir+i, __pgd(0));
#endif
flush_tlb_all();
}
#ifndef CONFIG_DISCONTIGMEM
void __init zone_sizes_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
unsigned int high, low;
low = max_low_pfn;
high = highend_pfn;
zones_size[ZONE_NORMAL] = low;
#ifdef CONFIG_HIGHMEM
zones_size[ZONE_HIGHMEM] = high - low;
#endif
free_area_init(zones_size);
}
#else
extern void zone_sizes_init(void);
#endif /* !CONFIG_DISCONTIGMEM */
/*
* - write protect new L1 pages in old pgd
* - write protect new pgd page in old pgd
* - write protect new pgd page in new pgd
* - write protect new L1 pages in new pgd
* - write protect old L1 pages in new pgd and write protect old pgd in
* new pgd
* - pin new pgd
* - switch to new pgd
* - unpin old pgd
* - make old L1 pages and old pgd page writeable in new pgd
*/
/*
* paging_init() sets up the page tables - note that the first 8MB are
* already mapped by head.S.
*
* This routines also unmaps the page at virtual kernel address 0, so
* that we can trap those pesky NULL-reference errors in the kernel.
*/
void __init paging_init(void)
{
pagetable_init();
wrprotect_bootpt((pgd_t *)start_info.pt_base, swapper_pg_dir, 1);
wrprotect_bootpt(swapper_pg_dir, swapper_pg_dir, 1);
flush_page_update_queue();
protect_bootpt_entries(swapper_pg_dir, swapper_pg_dir, 1, 0, 0);
protect_bootpt_entries((pgd_t *)start_info.pt_base, swapper_pg_dir,
1, 1, 1);
queue_pgd_pin(__pa(swapper_pg_dir));
flush_page_update_queue();
load_cr3(swapper_pg_dir);
__flush_tlb_all();
queue_pgd_unpin(__pa(start_info.pt_base));
flush_page_update_queue();
protect_bootpt_entries((pgd_t *)start_info.pt_base, swapper_pg_dir,
0, 1, 0);
wrprotect_bootpt((pgd_t *)start_info.pt_base, swapper_pg_dir, 0);
#ifdef CONFIG_X86_PAE
/*
* We will bail out later - printk doesn't work right now so
* the user would just see a hanging kernel.
*/
if (cpu_has_pae)
set_in_cr4(X86_CR4_PAE);
#endif
__flush_tlb_all();
kmap_init();
zone_sizes_init();
/* Switch to the real shared_info page, and clear the dummy page. */
flush_page_update_queue();
set_fixmap_ma(FIX_SHARED_INFO, start_info.shared_info);
HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
memset(empty_zero_page, 0, sizeof(empty_zero_page));
}
/*
* Test if the WP bit works in supervisor mode. It isn't supported on 386's
* and also on some strange 486's (NexGen etc.). All 586+'s are OK. This
* used to involve black magic jumps to work around some nasty CPU bugs,
* but fortunately the switch to using exceptions got rid of all that.
*/
void __init test_wp_bit(void)
{
printk("Checking if this processor honours the WP bit even in supervisor mode... ");
/* Any page-aligned address will do, the test is non-destructive */
__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
boot_cpu_data.wp_works_ok = do_test_wp_bit();
clear_fixmap(FIX_WP_TEST);
if (!boot_cpu_data.wp_works_ok) {
printk("No.\n");
#ifdef CONFIG_X86_WP_WORKS_OK
panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
#endif
} else {
printk("Ok.\n");
}
}
#ifndef CONFIG_DISCONTIGMEM
static void __init set_max_mapnr_init(void)
{
#ifdef CONFIG_HIGHMEM
highmem_start_page = pfn_to_page(highstart_pfn);
max_mapnr = num_physpages = highend_pfn;
#else
max_mapnr = num_physpages = max_low_pfn;
#endif
}
#define __free_all_bootmem() free_all_bootmem()
#else
#define __free_all_bootmem() free_all_bootmem_node(NODE_DATA(0))
extern void set_max_mapnr_init(void);
#endif /* !CONFIG_DISCONTIGMEM */
static struct kcore_list kcore_mem, kcore_vmalloc;
void __init mem_init(void)
{
extern int ppro_with_ram_bug(void);
int codesize, reservedpages, datasize, initsize;
int tmp;
int bad_ppro;
#ifndef CONFIG_DISCONTIGMEM
if (!mem_map)
BUG();
#endif
bad_ppro = ppro_with_ram_bug();
#ifdef CONFIG_HIGHMEM
/* check that fixmap and pkmap do not overlap */
if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n");
printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n",
PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START);
BUG();
}
#endif
set_max_mapnr_init();
#ifdef CONFIG_HIGHMEM
high_memory = (void *) __va(highstart_pfn * PAGE_SIZE);
#else
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
#endif
/* this will put all low memory onto the freelists */
totalram_pages += __free_all_bootmem();
reservedpages = 0;
for (tmp = 0; tmp < max_low_pfn; tmp++)
/*
* Only count reserved RAM pages
*/
if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
reservedpages++;
set_highmem_pages_init(bad_ppro);
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
VMALLOC_END-VMALLOC_START);
printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
num_physpages << (PAGE_SHIFT-10),
codesize >> 10,
reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
initsize >> 10,
(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
);
#ifdef CONFIG_X86_PAE
if (!cpu_has_pae)
panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
#endif
if (boot_cpu_data.wp_works_ok < 0)
test_wp_bit();
/*
* Subtle. SMP is doing it's boot stuff late (because it has to
* fork idle threads) - but it also needs low mappings for the
* protected-mode entry to work. We zap these entries only after
* the WP-bit has been tested.
*/
#ifndef CONFIG_SMP
zap_low_mappings();
#endif
}
kmem_cache_t *pgd_cache;
kmem_cache_t *pmd_cache;
void __init pgtable_cache_init(void)
{
if (PTRS_PER_PMD > 1) {
pmd_cache = kmem_cache_create("pmd",
PTRS_PER_PMD*sizeof(pmd_t),
PTRS_PER_PMD*sizeof(pmd_t),
0,
pmd_ctor,
NULL);
if (!pmd_cache)
panic("pgtable_cache_init(): cannot create pmd cache");
}
pgd_cache = kmem_cache_create("pgd",
PTRS_PER_PGD*sizeof(pgd_t),
PTRS_PER_PGD*sizeof(pgd_t),
0,
pgd_ctor,
pgd_dtor);
if (!pgd_cache)
panic("pgtable_cache_init(): Cannot create pgd cache");
}
/*
* This function cannot be __init, since exceptions don't work in that
* section. Put this after the callers, so that it cannot be inlined.
*/
static int do_test_wp_bit(void)
{
char tmp_reg;
int flag;
__asm__ __volatile__(
" movb %0,%1 \n"
"1: movb %1,%0 \n"
" xorl %2,%2 \n"
"2: \n"
".section __ex_table,\"a\"\n"
" .align 4 \n"
" .long 1b,2b \n"
".previous \n"
:"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
"=q" (tmp_reg),
"=r" (flag)
:"2" (1)
:"memory");
return flag;
}
void free_initmem(void)
{
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);
free_page(addr);
totalram_pages++;
}
printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (__init_end - __init_begin) >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < end)
printk (KERN_INFO "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
@@ -0,0 +1,319 @@
/*
* linux/arch/i386/mm/pgtable.c
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/fixmap.h>
#include <asm/e820.h>
#include <asm/tlb.h>
#include <asm/tlbflush.h>
#include <asm/io.h>
void show_mem(void)
{
int total = 0, reserved = 0;
int shared = 0, cached = 0;
int highmem = 0;
struct page *page;
pg_data_t *pgdat;
unsigned long i;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
for_each_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
page = pgdat->node_mem_map + i;
total++;
if (PageHighMem(page))
highmem++;
if (PageReserved(page))
reserved++;
else if (PageSwapCache(page))
cached++;
else if (page_count(page))
shared += page_count(page) - 1;
}
}
printk("%d pages of RAM\n", total);
printk("%d pages of HIGHMEM\n",highmem);
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
}
/*
* Associate a virtual page frame with a given physical page frame
* and protection flags for that frame.
*/
static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
pgd = swapper_pg_dir + pgd_index(vaddr);
if (pgd_none(*pgd)) {
BUG();
return;
}
pmd = pmd_offset(pgd, vaddr);
if (pmd_none(*pmd)) {
BUG();
return;
}
pte = pte_offset_kernel(pmd, vaddr);
/* <pfn,flags> stored as-is, to permit clearing entries */
set_pte(pte, pfn_pte(pfn, flags));
/*
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
__flush_tlb_one(vaddr);
}
/*
* Associate a virtual page frame with a given physical page frame
* and protection flags for that frame.
*/
static void set_pte_pfn_ma(unsigned long vaddr, unsigned long pfn,
pgprot_t flags)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
pgd = swapper_pg_dir + pgd_index(vaddr);
if (pgd_none(*pgd)) {
BUG();
return;
}
pmd = pmd_offset(pgd, vaddr);
if (pmd_none(*pmd)) {
BUG();
return;
}
pte = pte_offset_kernel(pmd, vaddr);
/* <pfn,flags> stored as-is, to permit clearing entries */
set_pte(pte, pfn_pte_ma(pfn, flags));
/*
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
__flush_tlb_one(vaddr);
}
/*
* Associate a large virtual page frame with a given physical page frame
* and protection flags for that frame. pfn is for the base of the page,
* vaddr is what the page gets mapped to - both must be properly aligned.
* The pmd must already be instantiated. Assumes PAE mode.
*/
void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
{
pgd_t *pgd;
pmd_t *pmd;
if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */
printk ("set_pmd_pfn: vaddr misaligned\n");
return; /* BUG(); */
}
if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */
printk ("set_pmd_pfn: pfn misaligned\n");
return; /* BUG(); */
}
pgd = swapper_pg_dir + pgd_index(vaddr);
if (pgd_none(*pgd)) {
printk ("set_pmd_pfn: pgd_none\n");
return; /* BUG(); */
}
pmd = pmd_offset(pgd, vaddr);
set_pmd(pmd, pfn_pmd(pfn, flags));
/*
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
__flush_tlb_one(vaddr);
}
void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
BUG();
return;
}
set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
}
void __set_fixmap_ma (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
{
unsigned long address = __fix_to_virt(idx);
if (idx >= __end_of_fixed_addresses) {
BUG();
return;
}
set_pte_pfn_ma(address, phys >> PAGE_SHIFT, flags);
}
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
if (pte) {
clear_page(pte);
__make_page_readonly(pte);
}
return pte;
}
struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
struct page *pte;
#ifdef CONFIG_HIGHPTE
pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT, 0);
#else
pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);
#endif
if (pte) {
clear_highpage(pte);
__make_page_readonly(phys_to_virt(page_to_phys(pte)));
/* XXXcl highmem */
}
return pte;
}
void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags)
{
memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
}
/*
* List of all pgd's needed for non-PAE so it can invalidate entries
* in both cached and uncached pgd's; not needed for PAE since the
* kernel pmd is shared. If PAE were not to share the pmd a similar
* tactic would be needed. This is essentially codepath-based locking
* against pageattr.c; it is the unique case in which a valid change
* of kernel pagetables can't be lazily synchronized by vmalloc faults.
* vmalloc faults work because attached pagetables are never freed.
* If the locking proves to be non-performant, a ticketing scheme with
* checks at dup_mmap(), exec(), and other mmlist addition points
* could be used. The locking scheme was chosen on the basis of
* manfred's recommendations and having no core impact whatsoever.
* -- wli
*/
spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
struct page *pgd_list;
static inline void pgd_list_add(pgd_t *pgd)
{
struct page *page = virt_to_page(pgd);
page->index = (unsigned long)pgd_list;
if (pgd_list)
pgd_list->private = (unsigned long)&page->index;
pgd_list = page;
page->private = (unsigned long)&pgd_list;
}
static inline void pgd_list_del(pgd_t *pgd)
{
struct page *next, **pprev, *page = virt_to_page(pgd);
next = (struct page *)page->index;
pprev = (struct page **)page->private;
*pprev = next;
if (next)
next->private = (unsigned long)pprev;
}
void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
{
unsigned long flags;
if (PTRS_PER_PMD == 1)
spin_lock_irqsave(&pgd_lock, flags);
memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
if (PTRS_PER_PMD > 1)
goto out;
pgd_list_add(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
out:
__make_page_readonly(pgd);
queue_pgd_pin(__pa(pgd));
flush_page_update_queue();
}
/* never called when PTRS_PER_PMD > 1 */
void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
{
unsigned long flags; /* can be called from interrupt context */
queue_pgd_unpin(__pa(pgd));
__make_page_writeable(pgd);
flush_page_update_queue();
if (PTRS_PER_PMD > 1)
return;
spin_lock_irqsave(&pgd_lock, flags);
pgd_list_del(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
}
pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
if (PTRS_PER_PMD == 1 || !pgd)
return pgd;
for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
if (!pmd)
goto out_oom;
set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd))));
}
return pgd;
out_oom:
for (i--; i >= 0; i--)
kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pgd_cache, pgd);
return NULL;
}
void pgd_free(pgd_t *pgd)
{
int i;
/* in the PAE case user pgd entries are overwritten before usage */
if (PTRS_PER_PMD > 1)
for (i = 0; i < USER_PTRS_PER_PGD; ++i)
kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
/* in the non-PAE case, clear_page_tables() clears user pgd entries */
kmem_cache_free(pgd_cache, pgd);
}
@@ -0,0 +1,12 @@
#
# Makefile for the linux kernel.
#
XENARCH := $(subst ",,$(CONFIG_XENARCH))
$(obj)/vmlinux.lds.s: arch/$(ARCH)/$(XENARCH)/kernel/vmlinux.lds.s
@ln -fsn $(srctree)/arch/$(ARCH)/$(XENARCH)/kernel/vmlinux.lds.s $@
extra-y += vmlinux.lds.s
obj-y := ctrl_if.o process.o reboot.o empty.o
@@ -0,0 +1,478 @@
/******************************************************************************
* ctrl_if.c
*
* Management functions for special interface to the domain controller.
*
* Copyright (c) 2004, K A Fraser
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm-xen/ctrl_if.h>
#include <asm-xen/evtchn.h>
#if 0
#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
__FILE__ , __LINE__ , ## _a )
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
/*
* Only used by initial domain which must create its own control-interface
* event channel. This value is picked up by the user-space domain controller
* via an ioctl.
*/
int initdom_ctrlif_domcontroller_port = -1;
static int ctrl_if_evtchn;
static int ctrl_if_irq;
static spinlock_t ctrl_if_lock;
static struct irqaction ctrl_if_irq_action;
static CONTROL_RING_IDX ctrl_if_tx_resp_cons;
static CONTROL_RING_IDX ctrl_if_rx_req_cons;
/* Incoming message requests. */
/* Primary message type -> message handler. */
static ctrl_msg_handler_t ctrl_if_rxmsg_handler[256];
/* Primary message type -> callback in process context? */
static unsigned long ctrl_if_rxmsg_blocking_context[256/sizeof(unsigned long)];
/* Is it late enough during bootstrap to use schedule_task()? */
static int safe_to_schedule_task;
#if 0 /* XXXcl tq */
/* Passed to schedule_task(). */
static struct tq_struct ctrl_if_rxmsg_deferred_tq;
#else
static struct work_struct ctrl_if_rxmsg_deferred_work;
#endif
/* Queue up messages to be handled in process context. */
static ctrl_msg_t ctrl_if_rxmsg_deferred[CONTROL_RING_SIZE];
static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_prod;
static CONTROL_RING_IDX ctrl_if_rxmsg_deferred_cons;
/* Incoming message responses: message identifier -> message handler/id. */
static struct {
ctrl_msg_handler_t fn;
unsigned long id;
} ctrl_if_txmsg_id_mapping[CONTROL_RING_SIZE];
#if 0 /* XXXcl tq */
static DECLARE_TASK_QUEUE(ctrl_if_tx_tq);
#else
static struct workqueue_struct *ctrl_if_tx_wq = NULL;
#endif
static DECLARE_WAIT_QUEUE_HEAD(ctrl_if_tx_wait);
static void __ctrl_if_tx_tasklet(unsigned long data);
static DECLARE_TASKLET(ctrl_if_tx_tasklet, __ctrl_if_tx_tasklet, 0);
static void __ctrl_if_rx_tasklet(unsigned long data);
static DECLARE_TASKLET(ctrl_if_rx_tasklet, __ctrl_if_rx_tasklet, 0);
#define get_ctrl_if() ((control_if_t *)((char *)HYPERVISOR_shared_info + 2048))
#define TX_FULL(_c) \
(((_c)->tx_req_prod - ctrl_if_tx_resp_cons) == CONTROL_RING_SIZE)
static void ctrl_if_notify_controller(void)
{
notify_via_evtchn(ctrl_if_evtchn);
}
static void ctrl_if_rxmsg_default_handler(ctrl_msg_t *msg, unsigned long id)
{
msg->length = 0;
ctrl_if_send_response(msg);
}
static void __ctrl_if_tx_tasklet(unsigned long data)
{
control_if_t *ctrl_if = get_ctrl_if();
ctrl_msg_t *msg;
int was_full = TX_FULL(ctrl_if);
while ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
{
msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)];
DPRINTK("Rx-Rsp %u/%u :: %d/%d\n",
ctrl_if_tx_resp_cons,
ctrl_if->tx_resp_prod,
msg->type, msg->subtype);
/* Execute the callback handler, if one was specified. */
if ( msg->id != 0xFF )
{
(*ctrl_if_txmsg_id_mapping[msg->id].fn)(
msg, ctrl_if_txmsg_id_mapping[msg->id].id);
smp_mb(); /* Execute, /then/ free. */
ctrl_if_txmsg_id_mapping[msg->id].fn = NULL;
}
/*
* Step over the message in the ring /after/ finishing reading it. As
* soon as the index is updated then the message may get blown away.
*/
smp_mb();
ctrl_if_tx_resp_cons++;
}
if ( was_full && !TX_FULL(ctrl_if) )
{
wake_up(&ctrl_if_tx_wait);
#if 0 /* XXXcl tq */
run_task_queue(&ctrl_if_tx_tq);
#endif
}
}
static void __ctrl_if_rxmsg_deferred(void *unused)
{
ctrl_msg_t *msg;
while ( ctrl_if_rxmsg_deferred_cons != ctrl_if_rxmsg_deferred_prod )
{
msg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(
ctrl_if_rxmsg_deferred_cons++)];
(*ctrl_if_rxmsg_handler[msg->type])(msg, 0);
}
}
static void __ctrl_if_rx_tasklet(unsigned long data)
{
control_if_t *ctrl_if = get_ctrl_if();
ctrl_msg_t msg, *pmsg;
while ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
{
pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)];
memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg));
DPRINTK("Rx-Req %u/%u :: %d/%d\n",
ctrl_if_rx_req_cons-1,
ctrl_if->rx_req_prod,
msg.type, msg.subtype);
if ( msg.length != 0 )
memcpy(msg.msg, pmsg->msg, msg.length);
if ( test_bit(msg.type, (unsigned long *)&ctrl_if_rxmsg_blocking_context) )
{
pmsg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(
ctrl_if_rxmsg_deferred_prod++)];
memcpy(pmsg, &msg, offsetof(ctrl_msg_t, msg) + msg.length);
#if 0 /* XXXcl tq */
schedule_task(&ctrl_if_rxmsg_deferred_tq);
#else
schedule_work(&ctrl_if_rxmsg_deferred_work);
#endif
}
else
{
(*ctrl_if_rxmsg_handler[msg.type])(&msg, 0);
}
}
}
static irqreturn_t ctrl_if_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
control_if_t *ctrl_if = get_ctrl_if();
if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
tasklet_schedule(&ctrl_if_tx_tasklet);
if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
tasklet_schedule(&ctrl_if_rx_tasklet);
return IRQ_HANDLED;
}
int ctrl_if_send_message_noblock(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id)
{
control_if_t *ctrl_if = get_ctrl_if();
unsigned long flags;
int i;
spin_lock_irqsave(&ctrl_if_lock, flags);
if ( TX_FULL(ctrl_if) )
{
spin_unlock_irqrestore(&ctrl_if_lock, flags);
return -EAGAIN;
}
msg->id = 0xFF;
if ( hnd != NULL )
{
for ( i = 0; ctrl_if_txmsg_id_mapping[i].fn != NULL; i++ )
continue;
ctrl_if_txmsg_id_mapping[i].fn = hnd;
ctrl_if_txmsg_id_mapping[i].id = id;
msg->id = i;
}
DPRINTK("Tx-Req %u/%u :: %d/%d\n",
ctrl_if->tx_req_prod,
ctrl_if_tx_resp_cons,
msg->type, msg->subtype);
memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)],
msg, sizeof(*msg));
wmb(); /* Write the message before letting the controller peek at it. */
ctrl_if->tx_req_prod++;
spin_unlock_irqrestore(&ctrl_if_lock, flags);
ctrl_if_notify_controller();
return 0;
}
int ctrl_if_send_message_block(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id,
long wait_state)
{
DECLARE_WAITQUEUE(wait, current);
int rc;
/* Fast path. */
if ( (rc = ctrl_if_send_message_noblock(msg, hnd, id)) != -EAGAIN )
return rc;
add_wait_queue(&ctrl_if_tx_wait, &wait);
for ( ; ; )
{
set_current_state(wait_state);
if ( (rc = ctrl_if_send_message_noblock(msg, hnd, id)) != -EAGAIN )
break;
rc = -ERESTARTSYS;
if ( signal_pending(current) && (wait_state == TASK_INTERRUPTIBLE) )
break;
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&ctrl_if_tx_wait, &wait);
return rc;
}
int ctrl_if_enqueue_space_callback(struct work_struct *work)
{
control_if_t *ctrl_if = get_ctrl_if();
/* Fast path. */
if ( !TX_FULL(ctrl_if) )
return 0;
#if 0 /* XXXcl tq */
(void)queue_task(task, &ctrl_if_tx_tq);
#else
if (ctrl_if_tx_wq)
(void)queue_work(ctrl_if_tx_wq, work);
else
return 1;
#endif
/*
* We may race execution of the task queue, so return re-checked status. If
* the task is not executed despite the ring being non-full then we will
* certainly return 'not full'.
*/
smp_mb();
return TX_FULL(ctrl_if);
}
void ctrl_if_send_response(ctrl_msg_t *msg)
{
control_if_t *ctrl_if = get_ctrl_if();
unsigned long flags;
ctrl_msg_t *dmsg;
/*
* NB. The response may the original request message, modified in-place.
* In this situation we may have src==dst, so no copying is required.
*/
spin_lock_irqsave(&ctrl_if_lock, flags);
DPRINTK("Tx-Rsp %u :: %d/%d\n",
ctrl_if->rx_resp_prod,
msg->type, msg->subtype);
dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)];
if ( dmsg != msg )
memcpy(dmsg, msg, sizeof(*msg));
wmb(); /* Write the message before letting the controller peek at it. */
ctrl_if->rx_resp_prod++;
spin_unlock_irqrestore(&ctrl_if_lock, flags);
ctrl_if_notify_controller();
}
int ctrl_if_register_receiver(
u8 type,
ctrl_msg_handler_t hnd,
unsigned int flags)
{
unsigned long _flags;
int inuse;
spin_lock_irqsave(&ctrl_if_lock, _flags);
inuse = (ctrl_if_rxmsg_handler[type] != ctrl_if_rxmsg_default_handler);
if ( inuse )
{
printk(KERN_INFO "Receiver %p already established for control "
"messages of type %d.\n", ctrl_if_rxmsg_handler[type], type);
}
else
{
ctrl_if_rxmsg_handler[type] = hnd;
clear_bit(type, (unsigned long *)&ctrl_if_rxmsg_blocking_context);
if ( flags == CALLBACK_IN_BLOCKING_CONTEXT )
{
set_bit(type, (unsigned long *)&ctrl_if_rxmsg_blocking_context);
if ( !safe_to_schedule_task )
BUG();
}
}
spin_unlock_irqrestore(&ctrl_if_lock, _flags);
return !inuse;
}
void ctrl_if_unregister_receiver(u8 type, ctrl_msg_handler_t hnd)
{
unsigned long flags;
spin_lock_irqsave(&ctrl_if_lock, flags);
if ( ctrl_if_rxmsg_handler[type] != hnd )
printk(KERN_INFO "Receiver %p is not registered for control "
"messages of type %d.\n", hnd, type);
else
ctrl_if_rxmsg_handler[type] = ctrl_if_rxmsg_default_handler;
spin_unlock_irqrestore(&ctrl_if_lock, flags);
/* Ensure that @hnd will not be executed after this function returns. */
tasklet_unlock_wait(&ctrl_if_rx_tasklet);
}
void ctrl_if_suspend(void)
{
free_irq(ctrl_if_irq, NULL);
unbind_evtchn_from_irq(ctrl_if_evtchn);
}
/** Reset the control interface progress pointers.
* Marks the queues empty if 'clear' non-zero.
*/
void ctrl_if_reset(int clear){
control_if_t *ctrl_if = get_ctrl_if();
if(clear){
*ctrl_if = (control_if_t){};
}
ctrl_if_tx_resp_cons = ctrl_if->tx_resp_prod;
ctrl_if_rx_req_cons = ctrl_if->rx_resp_prod;
}
void ctrl_if_resume(void)
{
if ( start_info.flags & SIF_INITDOMAIN )
{
/*
* The initial domain must create its own domain-controller link.
* The controller is probably not running at this point, but will
* pick up its end of the event channel from
*/
evtchn_op_t op;
op.cmd = EVTCHNOP_bind_interdomain;
op.u.bind_interdomain.dom1 = DOMID_SELF;
op.u.bind_interdomain.dom2 = DOMID_SELF;
if ( HYPERVISOR_event_channel_op(&op) != 0 )
BUG();
start_info.domain_controller_evtchn = op.u.bind_interdomain.port1;
initdom_ctrlif_domcontroller_port = op.u.bind_interdomain.port2;
}
ctrl_if_reset(0);
ctrl_if_evtchn = start_info.domain_controller_evtchn;
ctrl_if_irq = bind_evtchn_to_irq(ctrl_if_evtchn);
#define SA_STATIC_ACTION 0x01000000 /* so that free_irq() doesn't do kfree() */
memset(&ctrl_if_irq_action, 0, sizeof(ctrl_if_irq_action));
ctrl_if_irq_action.handler = ctrl_if_interrupt;
ctrl_if_irq_action.name = "ctrl-if";
ctrl_if_irq_action.flags = SA_STATIC_ACTION;
(void)setup_irq(ctrl_if_irq, &ctrl_if_irq_action);
}
void __init ctrl_if_init(void)
{
int i;
for ( i = 0; i < 256; i++ )
ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
#if 0 /* XXXcl tq */
ctrl_if_rxmsg_deferred_tq.routine = __ctrl_if_rxmsg_deferred;
#else
INIT_WORK(&ctrl_if_rxmsg_deferred_work, (void *)__ctrl_if_rxmsg_deferred,
NULL);
#endif
spin_lock_init(&ctrl_if_lock);
ctrl_if_reset(1);
ctrl_if_resume();
}
/* This is called after it is safe to call schedule_task(). */
static int __init ctrl_if_late_setup(void)
{
safe_to_schedule_task = 1;
ctrl_if_tx_wq = create_workqueue("ctrl_if_tx");
if (ctrl_if_tx_wq == NULL)
return 1; /* XXX */
return 0;
}
__initcall(ctrl_if_late_setup);
/*
* !! The following are DANGEROUS FUNCTIONS !!
* Use with care [for example, see xencons_force_flush()].
*/
int ctrl_if_transmitter_empty(void)
{
return (get_ctrl_if()->tx_req_prod == ctrl_if_tx_resp_cons);
}
void ctrl_if_discard_responses(void)
{
ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod;
}
@@ -0,0 +1,44 @@
#include <linux/string.h>
#include <asm/hypervisor.h>
#if 0
static __inline__ int HYPERVISOR_console_write(const char *str, int count)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_console_write),
"b" (str), "c" (count) : "memory" );
return ret;
}
#endif
#if 01
void
xen_puts(const char *str)
{
(void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(str), (char *)str);
}
asmlinkage int CLPRINTK(const char *fmt, ...)
{
va_list args;
int printk_len;
static char printk_buf[1024+1];
/* Emit the output into the temporary buffer */
va_start(args, fmt);
printk_len = vsnprintf(printk_buf, sizeof(printk_buf)-1, fmt, args);
va_end(args);
printk_buf[printk_len] = 0;
/* Send the processed output directly to Xen. */
(void)HYPERVISOR_console_io(CONSOLEIO_write, printk_len, printk_buf);
return 0;
}
#endif
@@ -0,0 +1,20 @@
#include <stdarg.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/platform.h>
#include <linux/pm.h>
void xen_cpu_idle (void)
{
// local_irq_disable();
if (need_resched()) {
// local_irq_enable();
return;
}
// local_irq_enable();
HYPERVISOR_yield();
}
@@ -0,0 +1,39 @@
#include <linux/module.h>
#include <asm/hypervisor.h>
int reboot_thru_bios = 0; /* for dmi_scan.c */
void machine_restart(char * __unused)
{
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
xencons_force_flush();
HYPERVISOR_reboot();
}
EXPORT_SYMBOL(machine_restart);
void machine_halt(void)
{
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
xencons_force_flush();
for ( ; ; ) /* loop without wasting cpu cycles */
{
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending = 0;
HYPERVISOR_block();
}
}
EXPORT_SYMBOL(machine_halt);
void machine_power_off(void)
{
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
xencons_force_flush();
HYPERVISOR_shutdown();
}
EXPORT_SYMBOL(machine_power_off);
@@ -0,0 +1,6 @@
obj-y += evtchn/
obj-y += console/
obj-y += block/
obj-y += net/
@@ -0,0 +1,6 @@
config XENBLOCK
tristate "Block device driver"
depends on ARCH_XEN
help
Block device driver for Xen
@@ -0,0 +1,3 @@
obj-y := vbd.o block.o
@@ -0,0 +1,653 @@
/******************************************************************************
* block.c
*
* XenLinux virtual block-device driver.
*
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
* Copyright (c) 2004, Christian Limpach
*/
#include "block.h"
#include <linux/cdrom.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <asm-xen/ctrl_if.h>
typedef unsigned char byte; /* from linux/ide.h */
#define BLKIF_STATE_CLOSED 0
#define BLKIF_STATE_DISCONNECTED 1
#define BLKIF_STATE_CONNECTED 2
static unsigned int blkif_state = BLKIF_STATE_CLOSED;
static unsigned int blkif_evtchn, blkif_irq;
static int blkif_control_rsp_valid;
static blkif_response_t blkif_control_rsp;
static blkif_ring_t *blk_ring;
static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
static BLKIF_RING_IDX req_prod; /* Private request producer. */
static blkif_ring_t *blk_ring_rec; /* Private copy of requests, used for
* recovery. Responses not stored here. */
static BLKIF_RING_IDX resp_cons_rec; /* Copy of response consumer, used for
* recovery */
static int recovery = 0; /* "Recovery in progress" flag. Protected
* by the blkif_io_lock */
/* We plug the I/O ring if the driver is suspended or if the ring is full. */
#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \
(blkif_state != BLKIF_STATE_CONNECTED))
/*
* Request queues with outstanding work, but ring is currently full.
* We need no special lock here, as we always access this with the
* blkif_io_lock held. We only need a small maximum list.
*/
#define MAX_PENDING 8
static request_queue_t *pending_queues[MAX_PENDING];
static int nr_pending;
static inline void flush_requests(void)
{
blk_ring->req_prod = req_prod;
notify_via_evtchn(blkif_evtchn);
}
#if 0
/*
* blkif_update_int/update-vbds_task - handle VBD update events.
* Schedule a task for keventd to run, which will update the VBDs and perform
* the corresponding updates to our view of VBD state.
*/
static struct tq_struct update_tq;
static void update_vbds_task(void *unused)
{
xlvbd_update_vbds();
}
#endif
int blkif_open(struct inode *inode, struct file *filep)
{
struct gendisk *gd = inode->i_bdev->bd_disk;
struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
/* Update of usage count is protected by per-device semaphore. */
di->mi->usage++;
return 0;
}
int blkif_release(struct inode *inode, struct file *filep)
{
struct gendisk *gd = inode->i_bdev->bd_disk;
struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
/*
* When usage drops to zero it may allow more VBD updates to occur.
* Update of usage count is protected by a per-device semaphore.
*/
if (--di->mi->usage == 0) {
#if 0
update_tq.routine = update_vbds_task;
schedule_task(&update_tq);
#endif
}
return 0;
}
int blkif_ioctl(struct inode *inode, struct file *filep,
unsigned command, unsigned long argument)
{
/* struct gendisk *gd = inode->i_bdev->bd_disk; */
DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
command, (long)argument, inode->i_rdev);
switch (command) {
case HDIO_GETGEO:
/* return ENOSYS to use defaults */
return -ENOSYS;
default:
printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
command);
return -ENOSYS;
}
return 0;
}
#if 0
/* check media change: should probably do something here in some cases :-) */
int blkif_check(kdev_t dev)
{
DPRINTK("blkif_check\n");
return 0;
}
int blkif_revalidate(kdev_t dev)
{
struct block_device *bd;
struct gendisk *gd;
xen_block_t *disk;
unsigned long capacity;
int i, rc = 0;
if ( (bd = bdget(dev)) == NULL )
return -EINVAL;
/*
* Update of partition info, and check of usage count, is protected
* by the per-block-device semaphore.
*/
down(&bd->bd_sem);
if ( ((gd = get_gendisk(dev)) == NULL) ||
((disk = xldev_to_xldisk(dev)) == NULL) ||
((capacity = gd->part[MINOR(dev)].nr_sects) == 0) )
{
rc = -EINVAL;
goto out;
}
if ( disk->usage > 1 )
{
rc = -EBUSY;
goto out;
}
/* Only reread partition table if VBDs aren't mapped to partitions. */
if ( !(gd->flags[MINOR(dev) >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) )
{
for ( i = gd->max_p - 1; i >= 0; i-- )
{
invalidate_device(dev+i, 1);
gd->part[MINOR(dev+i)].start_sect = 0;
gd->part[MINOR(dev+i)].nr_sects = 0;
gd->sizes[MINOR(dev+i)] = 0;
}
grok_partitions(gd, MINOR(dev)>>gd->minor_shift, gd->max_p, capacity);
}
out:
up(&bd->bd_sem);
bdput(bd);
return rc;
}
#endif
/*
* blkif_queue_request
*
* request block io
*
* id: for guest use only.
* operation: BLKIF_OP_{READ,WRITE,PROBE}
* buffer: buffer to read/write into. this should be a
* virtual address in the guest os.
*/
static int blkif_queue_request(struct request *req)
{
struct xlbd_disk_info *di =
(struct xlbd_disk_info *)req->rq_disk->private_data;
unsigned long buffer_ma;
blkif_request_t *ring_req;
struct bio *bio;
struct bio_vec *bvec;
int idx, s;
unsigned int fsect, lsect;
if (unlikely(blkif_state != BLKIF_STATE_CONNECTED))
return 1;
/* Fill out a communications ring structure. */
ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
ring_req->id = (unsigned long)req;
ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE :
BLKIF_OP_READ;
ring_req->sector_number = (blkif_sector_t)req->sector;
ring_req->device = di->xd_device;
s = 0;
ring_req->nr_segments = 0;
rq_for_each_bio(bio, req) {
bio_for_each_segment(bvec, bio, idx) {
buffer_ma =
phys_to_machine(page_to_phys(bvec->bv_page));
if (unlikely((buffer_ma & ((1<<9)-1)) != 0))
BUG();
fsect = bvec->bv_offset >> 9;
lsect = fsect + (bvec->bv_len >> 9) - 1;
if (unlikely(lsect > 7))
BUG();
ring_req->frame_and_sects[ring_req->nr_segments++] =
buffer_ma | (fsect << 3) | lsect;
s += bvec->bv_len >> 9;
}
}
req_prod++;
/* Keep a private copy so we can reissue requests when recovering. */
blk_ring_rec->ring[MASK_BLKIF_IDX(blk_ring_rec->req_prod)].req =
*ring_req;
blk_ring_rec->req_prod++;
return 0;
}
/*
* do_blkif_request
* read a block; request is in a request queue
*/
void do_blkif_request(request_queue_t *rq)
{
struct request *req;
int queued;
DPRINTK("Entered do_blkif_request\n");
queued = 0;
while ((req = elv_next_request(rq)) != NULL) {
if (!blk_fs_request(req)) {
end_request(req, 0);
continue;
}
if (BLKIF_RING_FULL) {
blk_stop_queue(rq);
break;
}
DPRINTK("do_blkif_request %p: cmd %p, sec %lx, (%u/%li) buffer:%p [%s]\n",
req, req->cmd, req->sector, req->current_nr_sectors,
req->nr_sectors, req->buffer,
rq_data_dir(req) ? "write" : "read");
blkdev_dequeue_request(req);
if (blkif_queue_request(req)) {
blk_stop_queue(rq);
break;
}
queued++;
}
if (queued != 0)
flush_requests();
}
static void kick_pending_request_queues(void)
{
/* We kick pending request queues if the ring is reasonably empty. */
if ( (nr_pending != 0) &&
((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) )
{
/* Attempt to drain the queue, but bail if the ring becomes full. */
while ( (nr_pending != 0) && !BLKIF_RING_FULL )
do_blkif_request(pending_queues[--nr_pending]);
}
}
static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct request *req;
blkif_response_t *bret;
BLKIF_RING_IDX i;
unsigned long flags;
spin_lock_irqsave(&blkif_io_lock, flags);
if (unlikely(blkif_state == BLKIF_STATE_CLOSED || recovery)) {
printk("Bailed out\n");
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
for (i = resp_cons; i != blk_ring->resp_prod; i++) {
bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
switch (bret->operation) {
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
if (unlikely(bret->status != BLKIF_RSP_OKAY))
DPRINTK("Bad return from blkdev data request: %lx\n",
bret->status);
req = (struct request *)bret->id;
/* XXXcl pass up status */
if (unlikely(end_that_request_first(req, 1,
req->hard_nr_sectors)))
BUG();
end_that_request_last(req);
break;
case BLKIF_OP_PROBE:
memcpy(&blkif_control_rsp, bret, sizeof(*bret));
blkif_control_rsp_valid = 1;
break;
default:
BUG();
}
}
resp_cons = i;
resp_cons_rec = i;
if (xlbd_blk_queue &&
test_bit(QUEUE_FLAG_STOPPED, &xlbd_blk_queue->queue_flags)) {
blk_start_queue(xlbd_blk_queue);
/* XXXcl call to request_fn should not be needed but
* we get stuck without... needs investigating
*/
xlbd_blk_queue->request_fn(xlbd_blk_queue);
}
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
{
unsigned long flags;
retry:
while ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
spin_lock_irqsave(&blkif_io_lock, flags);
if ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
{
spin_unlock_irqrestore(&blkif_io_lock, flags);
goto retry;
}
memcpy(&blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req, req, sizeof(*req));
memcpy(&blk_ring_rec->ring[MASK_BLKIF_IDX(blk_ring_rec->req_prod++)].req,
req, sizeof(*req));
req_prod++;
flush_requests();
spin_unlock_irqrestore(&blkif_io_lock, flags);
while ( !blkif_control_rsp_valid )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
memcpy(rsp, &blkif_control_rsp, sizeof(*rsp));
blkif_control_rsp_valid = 0;
}
static void blkif_status_change(blkif_fe_interface_status_changed_t *status)
{
ctrl_msg_t cmsg;
blkif_fe_interface_connect_t up;
if ( status->handle != 0 )
{
printk(KERN_WARNING "Status change on unsupported blkif %d\n",
status->handle);
return;
}
switch ( status->status )
{
case BLKIF_INTERFACE_STATUS_DESTROYED:
printk(KERN_WARNING "Unexpected blkif-DESTROYED message in state %d\n",
blkif_state);
break;
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
if ( blkif_state != BLKIF_STATE_CLOSED )
{
printk(KERN_WARNING "Unexpected blkif-DISCONNECTED message"
" in state %d\n", blkif_state);
printk(KERN_INFO "VBD driver recovery in progress\n");
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&blkif_io_lock);
recovery = 1;
blkif_state = BLKIF_STATE_DISCONNECTED;
spin_unlock_irq(&blkif_io_lock);
/* Free resources associated with old device channel. */
free_page((unsigned long)blk_ring);
free_irq(blkif_irq, NULL);
unbind_evtchn_from_irq(blkif_evtchn);
}
/* Move from CLOSED to DISCONNECTED state. */
blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
blkif_state = BLKIF_STATE_DISCONNECTED;
/* Construct an interface-CONNECT message for the domain controller. */
cmsg.type = CMSG_BLKIF_FE;
cmsg.subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT;
cmsg.length = sizeof(blkif_fe_interface_connect_t);
up.handle = 0;
up.shmem_frame = virt_to_machine(blk_ring) >> PAGE_SHIFT;
memcpy(cmsg.msg, &up, sizeof(up));
/* Tell the controller to bring up the interface. */
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
break;
case BLKIF_INTERFACE_STATUS_CONNECTED:
if ( blkif_state == BLKIF_STATE_CLOSED )
{
printk(KERN_WARNING "Unexpected blkif-CONNECTED message"
" in state %d\n", blkif_state);
break;
}
blkif_evtchn = status->evtchn;
blkif_irq = bind_evtchn_to_irq(blkif_evtchn);
(void)request_irq(blkif_irq, blkif_int, 0, "blkif", NULL);
if ( recovery )
{
int i;
/* Shouldn't need the blkif_io_lock here - the device is
* plugged and the recovery flag prevents the interrupt handler
* changing anything. */
/* Reissue requests from the private block ring. */
for ( i = 0;
resp_cons_rec < blk_ring_rec->req_prod;
resp_cons_rec++, i++ )
{
blk_ring->ring[i].req
= blk_ring_rec->ring[MASK_BLKIF_IDX(resp_cons_rec)].req;
}
/* Reset the private block ring to match the new ring. */
memcpy(blk_ring_rec, blk_ring, sizeof(*blk_ring));
resp_cons_rec = 0;
/* blk_ring->req_prod will be set when we flush_requests().*/
blk_ring_rec->req_prod = req_prod = i;
wmb();
/* Switch off recovery mode, using a memory barrier to ensure that
* it's seen before we flush requests - we don't want to miss any
* interrupts. */
recovery = 0;
wmb();
/* Kicks things back into life. */
flush_requests();
}
else
{
/* Probe for discs that are attached to the interface. */
xlvbd_init();
}
blkif_state = BLKIF_STATE_CONNECTED;
/* Kick pending requests. */
spin_lock_irq(&blkif_io_lock);
kick_pending_request_queues();
spin_unlock_irq(&blkif_io_lock);
break;
default:
printk(KERN_WARNING "Status change to unknown value %d\n",
status->status);
break;
}
}
static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
{
switch ( msg->subtype )
{
case CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED:
if ( msg->length != sizeof(blkif_fe_interface_status_changed_t) )
goto parse_error;
blkif_status_change((blkif_fe_interface_status_changed_t *)
&msg->msg[0]);
break;
#if 0
case CMSG_BLKIF_FE_VBD_STATUS_CHANGED:
update_tq.routine = update_vbds_task;
schedule_task(&update_tq);
break;
#endif
default:
goto parse_error;
}
ctrl_if_send_response(msg);
return;
parse_error:
msg->length = 0;
ctrl_if_send_response(msg);
}
int __init xlblk_init(void)
{
ctrl_msg_t cmsg;
blkif_fe_driver_status_changed_t st;
if ( (start_info.flags & SIF_INITDOMAIN)
|| (start_info.flags & SIF_BLK_BE_DOMAIN) )
return 0;
printk(KERN_INFO "Initialising Xen virtual block device\n");
blk_ring_rec = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
memset(blk_ring_rec, 0, sizeof(*blk_ring_rec));
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
/* Send a driver-UP notification to the domain controller. */
cmsg.type = CMSG_BLKIF_FE;
cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED;
cmsg.length = sizeof(blkif_fe_driver_status_changed_t);
st.status = BLKIF_DRIVER_STATUS_UP;
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
/*
* We should read 'nr_interfaces' from response message and wait
* for notifications before proceeding. For now we assume that we
* will be notified of exactly one interface.
*/
while ( blkif_state != BLKIF_STATE_CONNECTED )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
return 0;
#if 0
int error;
reset_xlblk_interface();
xlblk_response_irq = bind_virq_to_irq(VIRQ_BLKDEV);
xlblk_update_irq = bind_virq_to_irq(VIRQ_VBD_UPD);
error = request_irq(xlblk_response_irq, xlblk_response_int,
SA_SAMPLE_RANDOM, "blkdev", NULL);
if (error) {
printk(KERN_ALERT "Could not allocate receive interrupt\n");
goto fail;
}
error = request_irq(xlblk_update_irq, xlblk_update_int,
0, "blkdev", NULL);
if (error) {
printk(KERN_ALERT
"Could not allocate block update interrupt\n");
goto fail;
}
(void)xlvbd_init();
return 0;
fail:
return error;
#endif
}
static void __exit xlblk_cleanup(void)
{
/* XXX FIXME */
BUG();
#if 0
/* xlvbd_cleanup(); */
free_irq(xlblk_response_irq, NULL);
free_irq(xlblk_update_irq, NULL);
unbind_virq_from_irq(VIRQ_BLKDEV);
unbind_virq_from_irq(VIRQ_VBD_UPD);
#endif
}
module_init(xlblk_init);
module_exit(xlblk_cleanup);
void blkdev_suspend(void)
{
}
void blkdev_resume(void)
{
}
@@ -0,0 +1,92 @@
/******************************************************************************
* block.h
*
* Shared definitions between all levels of XenLinux Virtual block devices.
*/
#ifndef __XEN_DRIVERS_BLOCK_H__
#define __XEN_DRIVERS_BLOCK_H__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/major.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/hypervisor-ifs/hypervisor-if.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm-xen/blkif.h>
#if 0
#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
#else
#define DPRINTK(_f, _a...) ((void)0)
#endif
#if 0
#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
#else
#define DPRINTK_IOCTL(_f, _a...) ((void)0)
#endif
struct xlbd_type_info {
int partn_shift;
int devs_per_major;
int hardsect_size;
int max_sectors;
char *name;
};
/*
* We have one of these per vbd, whether ide, scsi or 'other'. They
* hang in private_data off the gendisk structure. We may end up
* putting all kinds of interesting stuff here :-)
*/
struct xlbd_major_info {
int major;
int usage;
int xd_device;
struct xlbd_type_info *type;
};
struct xlbd_disk_info {
int xd_device;
struct xlbd_major_info *mi;
};
typedef struct xen_block {
int usage;
} xen_block_t;
extern struct request_queue *xlbd_blk_queue;
extern spinlock_t blkif_io_lock;
extern int blkif_open(struct inode *inode, struct file *filep);
extern int blkif_release(struct inode *inode, struct file *filep);
extern int blkif_ioctl(struct inode *inode, struct file *filep,
unsigned command, unsigned long argument);
extern int blkif_check(dev_t dev);
extern int blkif_revalidate(dev_t dev);
extern void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp);
extern void do_blkif_request (request_queue_t *rq);
extern void xlvbd_update_vbds(void);
/* Virtual block-device subsystem. */
extern int xlvbd_init(void);
extern void xlvbd_cleanup(void);
#endif /* __XEN_DRIVERS_BLOCK_H__ */
@@ -0,0 +1,530 @@
/******************************************************************************
* vbd.c
*
* XenLinux virtual block-device driver (xvd).
*
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
* Copyright (c) 2004, Christian Limpach
*/
#include "block.h"
#include <linux/blkdev.h>
/*
* For convenience we distinguish between ide, scsi and 'other' (i.e.
* potentially combinations of the two) in the naming scheme and in a few
* other places (like default readahead, etc).
*/
#define NUM_IDE_MAJORS 10
#define NUM_SCSI_MAJORS 9
#define NUM_VBD_MAJORS 1
static struct xlbd_type_info xlbd_ide_type = {
.partn_shift = 6,
// XXXcl todo blksize_size[major] = 1024;
.hardsect_size = 512,
.max_sectors = 128, /* 'hwif->rqsize' if we knew it */
// XXXcl todo read_ahead[major] = 8; /* from drivers/ide/ide-probe.c */
.name = "hd",
};
static struct xlbd_type_info xlbd_scsi_type = {
.partn_shift = 4,
// XXXcl todo blksize_size[major] = 1024; /* XXX 512; */
.hardsect_size = 512,
.max_sectors = 128*8, /* XXX 128; */
// XXXcl todo read_ahead[major] = 0; /* XXX 8; -- guessing */
.name = "sd",
};
static struct xlbd_type_info xlbd_vbd_type = {
.partn_shift = 4,
// XXXcl todo blksize_size[major] = 512;
.hardsect_size = 512,
.max_sectors = 128,
// XXXcl todo read_ahead[major] = 8;
.name = "xvd",
};
/* XXXcl handle cciss after finding out why it's "hacked" in */
static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
NUM_VBD_MAJORS];
/* Information about our VBDs. */
#define MAX_VBDS 64
static int nr_vbds;
static vdisk_t *vbd_info;
struct request_queue *xlbd_blk_queue = NULL;
#define MAJOR_XEN(dev) ((dev)>>8)
#define MINOR_XEN(dev) ((dev) & 0xff)
static struct block_device_operations xlvbd_block_fops =
{
.owner = THIS_MODULE,
.open = blkif_open,
.release = blkif_release,
.ioctl = blkif_ioctl,
#if 0
check_media_change: blkif_check,
revalidate: blkif_revalidate,
#endif
};
spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
static int xlvbd_get_vbd_info(vdisk_t *disk_info)
{
vdisk_t *buf = (vdisk_t *)__get_free_page(GFP_KERNEL);
blkif_request_t req;
blkif_response_t rsp;
int nr;
memset(&req, 0, sizeof(req));
req.operation = BLKIF_OP_PROBE;
req.nr_segments = 1;
req.frame_and_sects[0] = virt_to_machine(buf) | 7;
blkif_control_send(&req, &rsp);
if ( rsp.status <= 0 )
{
printk(KERN_ALERT "Could not probe disks (%d)\n", rsp.status);
return -1;
}
if ( (nr = rsp.status) > MAX_VBDS )
nr = MAX_VBDS;
memcpy(disk_info, buf, nr * sizeof(vdisk_t));
return nr;
}
static struct xlbd_major_info *xlbd_get_major_info(int xd_device, int *minor)
{
int mi_idx, new_major;
int xd_major = MAJOR_XEN(xd_device);
int xd_minor = MINOR_XEN(xd_device);
*minor = xd_minor;
switch (xd_major) {
case IDE0_MAJOR: mi_idx = 0; new_major = IDE0_MAJOR; break;
case IDE1_MAJOR: mi_idx = 1; new_major = IDE1_MAJOR; break;
case IDE2_MAJOR: mi_idx = 2; new_major = IDE2_MAJOR; break;
case IDE3_MAJOR: mi_idx = 3; new_major = IDE3_MAJOR; break;
case IDE4_MAJOR: mi_idx = 4; new_major = IDE4_MAJOR; break;
case IDE5_MAJOR: mi_idx = 5; new_major = IDE5_MAJOR; break;
case IDE6_MAJOR: mi_idx = 6; new_major = IDE6_MAJOR; break;
case IDE7_MAJOR: mi_idx = 7; new_major = IDE7_MAJOR; break;
case IDE8_MAJOR: mi_idx = 8; new_major = IDE8_MAJOR; break;
case IDE9_MAJOR: mi_idx = 9; new_major = IDE9_MAJOR; break;
case SCSI_DISK0_MAJOR: mi_idx = 10; new_major = SCSI_DISK0_MAJOR; break;
case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
mi_idx = 11 + xd_major - SCSI_DISK1_MAJOR;
new_major = SCSI_DISK1_MAJOR + xd_major - SCSI_DISK1_MAJOR;
break;
case SCSI_CDROM_MAJOR: mi_idx = 18; new_major = SCSI_CDROM_MAJOR; break;
default: mi_idx = 19; new_major = 0;/* XXXcl notyet */ break;
}
if (major_info[mi_idx])
return major_info[mi_idx];
major_info[mi_idx] = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
if (major_info[mi_idx] == NULL)
return NULL;
memset(major_info[mi_idx], 0, sizeof(struct xlbd_major_info));
switch (mi_idx) {
case 0 ... (NUM_IDE_MAJORS - 1):
major_info[mi_idx]->type = &xlbd_ide_type;
break;
case NUM_IDE_MAJORS ... (NUM_IDE_MAJORS + NUM_SCSI_MAJORS - 1):
major_info[mi_idx]->type = &xlbd_scsi_type;
break;
case (NUM_IDE_MAJORS + NUM_SCSI_MAJORS) ...
(NUM_IDE_MAJORS + NUM_SCSI_MAJORS + NUM_VBD_MAJORS - 1):
major_info[mi_idx]->type = &xlbd_vbd_type;
break;
}
major_info[mi_idx]->major = new_major;
if (register_blkdev(major_info[mi_idx]->major, major_info[mi_idx]->type->name)) {
printk(KERN_ALERT "XL VBD: can't get major %d with name %s\n",
major_info[mi_idx]->major, major_info[mi_idx]->type->name);
goto out;
}
devfs_mk_dir(major_info[mi_idx]->type->name);
return major_info[mi_idx];
out:
kfree(major_info[mi_idx]);
major_info[mi_idx] = NULL;
return NULL;
}
static struct gendisk *xlvbd_get_gendisk(struct xlbd_major_info *mi,
int xd_minor, vdisk_t *xd)
{
struct gendisk *gd;
struct xlbd_disk_info *di;
int device, partno;
device = MKDEV(mi->major, xd_minor);
gd = get_gendisk(device, &partno);
if (gd)
return gd;
di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
if (di == NULL)
return NULL;
di->mi = mi;
di->xd_device = xd->device;
/* Construct an appropriate gendisk structure. */
gd = alloc_disk(1);
if (gd == NULL)
goto out;
gd->major = mi->major;
gd->first_minor = xd_minor;
gd->fops = &xlvbd_block_fops;
gd->private_data = di;
sprintf(gd->disk_name, "%s%c%d", mi->type->name,
'a' + (xd_minor >> mi->type->partn_shift),
xd_minor & ((1 << mi->type->partn_shift) - 1));
/* sprintf(gd->devfs_name, "%s%s/disc%d", mi->type->name, , ); XXXdevfs */
set_capacity(gd, xd->capacity);
if (xlbd_blk_queue == NULL) {
xlbd_blk_queue = blk_init_queue(do_blkif_request,
&blkif_io_lock);
if (xlbd_blk_queue == NULL)
goto out;
elevator_init(xlbd_blk_queue, &elevator_noop);
/*
* Turn off barking 'headactive' mode. We dequeue
* buffer heads as soon as we pass them to back-end
* driver.
*/
blk_queue_headactive(xlbd_blk_queue, 0); /* XXXcl: noop according to blkdev.h */
blk_queue_hardsect_size(xlbd_blk_queue,
mi->type->hardsect_size);
blk_queue_max_sectors(xlbd_blk_queue, mi->type->max_sectors); /* 'hwif->rqsize' if we knew it */
/* XXXcl: set mask to PAGE_SIZE for now, to improve either use
- blk_queue_merge_bvec to merge requests with adjacent ma's
- the tags infrastructure
- the dma infrastructure
*/
blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
blk_queue_max_phys_segments(xlbd_blk_queue,
BLKIF_MAX_SEGMENTS_PER_REQUEST);
blk_queue_max_hw_segments(xlbd_blk_queue,
BLKIF_MAX_SEGMENTS_PER_REQUEST); /* XXXcl not needed? */
}
gd->queue = xlbd_blk_queue;
add_disk(gd);
return gd;
out:
if (gd)
del_gendisk(gd);
kfree(di);
return NULL;
}
/*
* xlvbd_init_device - initialise a VBD device
* @disk: a vdisk_t describing the VBD
*
* Takes a vdisk_t * that describes a VBD the domain has access to.
* Performs appropriate initialisation and registration of the device.
*
* Care needs to be taken when making re-entrant calls to ensure that
* corruption does not occur. Also, devices that are in use should not have
* their details updated. This is the caller's responsibility.
*/
static int xlvbd_init_device(vdisk_t *xd)
{
struct block_device *bd;
struct gendisk *gd;
struct xlbd_major_info *mi;
int device;
int minor;
int err = -ENOMEM;
mi = xlbd_get_major_info(xd->device, &minor);
if (mi == NULL)
return -EPERM;
device = MKDEV(mi->major, minor);
if ((bd = bdget(device)) == NULL)
return -EPERM;
/*
* Update of partition info, and check of usage count, is protected
* by the per-block-device semaphore.
*/
down(&bd->bd_sem);
gd = xlvbd_get_gendisk(mi, minor, xd);
if (mi == NULL) {
err = -EPERM;
goto out;
}
if (VDISK_READONLY(xd->info))
set_disk_ro(gd, 1);
/* Some final fix-ups depending on the device type */
switch (VDISK_TYPE(xd->info)) {
case VDISK_TYPE_CDROM:
gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
/* FALLTHROUGH */
case VDISK_TYPE_FLOPPY:
case VDISK_TYPE_TAPE:
gd->flags |= GENHD_FL_REMOVABLE;
break;
case VDISK_TYPE_DISK:
break;
default:
printk(KERN_ALERT "XenLinux: unknown device type %d\n",
VDISK_TYPE(xd->info));
break;
}
err = 0;
out:
up(&bd->bd_sem);
bdput(bd);
return err;
}
#if 0
/*
* xlvbd_remove_device - remove a device node if possible
* @device: numeric device ID
*
* Updates the gendisk structure and invalidates devices.
*
* This is OK for now but in future, should perhaps consider where this should
* deallocate gendisks / unregister devices.
*/
static int xlvbd_remove_device(int device)
{
int i, rc = 0, minor = MINOR(device);
struct gendisk *gd;
struct block_device *bd;
xen_block_t *disk = NULL;
if ( (bd = bdget(device)) == NULL )
return -1;
/*
* Update of partition info, and check of usage count, is protected
* by the per-block-device semaphore.
*/
down(&bd->bd_sem);
if ( ((gd = get_gendisk(device)) == NULL) ||
((disk = xldev_to_xldisk(device)) == NULL) )
BUG();
if ( disk->usage != 0 )
{
printk(KERN_ALERT "VBD removal failed - in use [dev=%x]\n", device);
rc = -1;
goto out;
}
if ( (minor & (gd->max_p-1)) != 0 )
{
/* 1: The VBD is mapped to a partition rather than a whole unit. */
invalidate_device(device, 1);
gd->part[minor].start_sect = 0;
gd->part[minor].nr_sects = 0;
gd->sizes[minor] = 0;
/* Clear the consists-of-virtual-partitions flag if possible. */
gd->flags[minor >> gd->minor_shift] &= ~GENHD_FL_VIRT_PARTNS;
for ( i = 1; i < gd->max_p; i++ )
if ( gd->sizes[(minor & ~(gd->max_p-1)) + i] != 0 )
gd->flags[minor >> gd->minor_shift] |= GENHD_FL_VIRT_PARTNS;
/*
* If all virtual partitions are now gone, and a 'whole unit' VBD is
* present, then we can try to grok the unit's real partition table.
*/
if ( !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) &&
(gd->sizes[minor & ~(gd->max_p-1)] != 0) &&
!(gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE) )
{
register_disk(gd,
device&~(gd->max_p-1),
gd->max_p,
&xlvbd_block_fops,
gd->part[minor&~(gd->max_p-1)].nr_sects);
}
}
else
{
/*
* 2: The VBD is mapped to an entire 'unit'. Clear all partitions.
* NB. The partition entries are only cleared if there are no VBDs
* mapped to individual partitions on this unit.
*/
i = gd->max_p - 1; /* Default: clear subpartitions as well. */
if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
i = 0; /* 'Virtual' mode: only clear the 'whole unit' entry. */
while ( i >= 0 )
{
invalidate_device(device+i, 1);
gd->part[minor+i].start_sect = 0;
gd->part[minor+i].nr_sects = 0;
gd->sizes[minor+i] = 0;
i--;
}
}
out:
up(&bd->bd_sem);
bdput(bd);
return rc;
}
/*
* xlvbd_update_vbds - reprobes the VBD status and performs updates driver
* state. The VBDs need to be updated in this way when the domain is
* initialised and also each time we receive an XLBLK_UPDATE event.
*/
void xlvbd_update_vbds(void)
{
int i, j, k, old_nr, new_nr;
vdisk_t *old_info, *new_info, *merged_info;
old_info = vbd_info;
old_nr = nr_vbds;
new_info = kmalloc(MAX_VBDS * sizeof(vdisk_t), GFP_KERNEL);
if ( unlikely(new_nr = xlvbd_get_vbd_info(new_info)) < 0 )
{
kfree(new_info);
return;
}
/*
* Final list maximum size is old list + new list. This occurs only when
* old list and new list do not overlap at all, and we cannot yet destroy
* VBDs in the old list because the usage counts are busy.
*/
merged_info = kmalloc((old_nr + new_nr) * sizeof(vdisk_t), GFP_KERNEL);
/* @i tracks old list; @j tracks new list; @k tracks merged list. */
i = j = k = 0;
while ( (i < old_nr) && (j < new_nr) )
{
if ( old_info[i].device < new_info[j].device )
{
if ( xlvbd_remove_device(old_info[i].device) != 0 )
memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
i++;
}
else if ( old_info[i].device > new_info[j].device )
{
if ( xlvbd_init_device(&new_info[j]) == 0 )
memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
j++;
}
else
{
if ( ((old_info[i].capacity == new_info[j].capacity) &&
(old_info[i].info == new_info[j].info)) ||
(xlvbd_remove_device(old_info[i].device) != 0) )
memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
else if ( xlvbd_init_device(&new_info[j]) == 0 )
memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
i++; j++;
}
}
for ( ; i < old_nr; i++ )
{
if ( xlvbd_remove_device(old_info[i].device) != 0 )
memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
}
for ( ; j < new_nr; j++ )
{
if ( xlvbd_init_device(&new_info[j]) == 0 )
memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
}
vbd_info = merged_info;
nr_vbds = k;
kfree(old_info);
kfree(new_info);
}
#endif
/*
* Set up all the linux device goop for the virtual block devices
* (vbd's) that we know about. Note that although from the backend
* driver's p.o.v. VBDs are addressed simply an opaque 16-bit device
* number, the domain creation tools conventionally allocate these
* numbers to correspond to those used by 'real' linux -- this is just
* for convenience as it means e.g. that the same /etc/fstab can be
* used when booting with or without Xen.
*/
int xlvbd_init(void)
{
int i;
/*
* If compiled as a module, we don't support unloading yet. We
* therefore permanently increment the reference count to
* disallow it.
*/
MOD_INC_USE_COUNT;
memset(major_info, 0, sizeof(major_info));
for (i = 0; i < sizeof(major_info) / sizeof(major_info[0]); i++) {
}
vbd_info = kmalloc(MAX_VBDS * sizeof(vdisk_t), GFP_KERNEL);
nr_vbds = xlvbd_get_vbd_info(vbd_info);
if (nr_vbds < 0) {
kfree(vbd_info);
vbd_info = NULL;
nr_vbds = 0;
} else {
for (i = 0; i < nr_vbds; i++)
xlvbd_init_device(&vbd_info[i]);
}
return 0;
}
@@ -0,0 +1,2 @@
obj-y := console.o
@@ -0,0 +1,618 @@
/******************************************************************************
* console.c
*
* Virtual console driver.
*
* Copyright (c) 2002-2004, K A Fraser.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/console.h>
#include <asm-xen/evtchn.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/hypervisor.h>
#include <asm/hypervisor-ifs/event_channel.h>
#include <asm-xen/ctrl_if.h>
/*
* Modes:
* 'xencons=off' [XC_OFF]: Console is disabled.
* 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
* 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
* [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
*
* NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
* warnings from standard distro startup scripts.
*/
static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
static int __init xencons_setup(char *str)
{
if ( !strcmp(str, "tty") )
xc_mode = XC_TTY;
else if ( !strcmp(str, "ttyS") )
xc_mode = XC_SERIAL;
else if ( !strcmp(str, "off") )
xc_mode = XC_OFF;
return 1;
}
__setup("xencons", xencons_setup);
/* The kernel and user-land drivers share a common transmit buffer. */
#define WBUF_SIZE 4096
#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
static char wbuf[WBUF_SIZE];
static unsigned int wc, wp; /* write_cons, write_prod */
/* This lock protects accesses to the common transmit buffer. */
static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
static struct tty_driver *xencons_driver;
#define NUM_XENCONS 1
/* Common transmit-kick routine. */
static void __xencons_tx_flush(void);
/* This task is used to defer sending console data until there is space. */
static void xencons_tx_flush_task_routine(void *data);
#if 0 /* XXXcl tq */
static struct tq_struct xencons_tx_flush_task = {
routine: xencons_tx_flush_task_routine
};
#else
static DECLARE_WORK(xencons_tx_flush_task, xencons_tx_flush_task_routine,
NULL);
#endif
/******************** Kernel console driver ********************************/
static void kcons_write(
struct console *c, const char *s, unsigned int count)
{
int i;
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
for ( i = 0; i < count; i++ )
{
if ( (wp - wc) >= (WBUF_SIZE - 1) )
break;
if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
wbuf[WBUF_MASK(wp++)] = '\r';
}
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
}
static void kcons_write_dom0(
struct console *c, const char *s, unsigned int count)
{
int rc;
while ( count > 0 )
{
if ( (rc = HYPERVISOR_console_io(CONSOLEIO_write, count, (char *)s)) > 0 )
{
count -= rc;
s += rc;
}
else
break;
}
}
static struct tty_driver *kcons_device(struct console *c, int *index)
{
*index = c->index;
return xencons_driver;
}
static struct console kcons_info = {
device: kcons_device,
flags: CON_PRINTBUFFER,
index: -1
};
static int __init xen_console_init(void)
{
if ( start_info.flags & SIF_INITDOMAIN )
{
if ( xc_mode == XC_DEFAULT )
xc_mode = XC_SERIAL;
kcons_info.write = kcons_write_dom0;
}
else
{
if ( xc_mode == XC_DEFAULT )
xc_mode = XC_TTY;
kcons_info.write = kcons_write;
}
if ( xc_mode == XC_OFF )
return 0;
if ( xc_mode == XC_SERIAL )
strcpy(kcons_info.name, "ttyS");
else
strcpy(kcons_info.name, "tty");
register_console(&kcons_info);
return 0;
}
console_initcall(xen_console_init);
/*** Useful function for console debugging -- goes straight to Xen. ***/
asmlinkage int xprintk(const char *fmt, ...)
{
va_list args;
int printk_len;
static char printk_buf[1024];
/* Emit the output into the temporary buffer */
va_start(args, fmt);
printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
va_end(args);
/* Send the processed output directly to Xen. */
kcons_write_dom0(NULL, printk_buf, printk_len);
return 0;
}
/*** Forcibly flush console data before dying. ***/
void xencons_force_flush(void)
{
ctrl_msg_t msg;
int sz;
/* Emergency console is synchronous, so there's nothing to flush. */
if ( start_info.flags & SIF_INITDOMAIN )
return;
/*
* We use dangerous control-interface functions that require a quiescent
* system and no interrupts. Try to ensure this with a global cli().
*/
cli();
/* Spin until console data is flushed through to the domain controller. */
while ( (wc != wp) && !ctrl_if_transmitter_empty() )
{
/* Interrupts are disabled -- we must manually reap responses. */
ctrl_if_discard_responses();
if ( (sz = wp - wc) == 0 )
continue;
if ( sz > sizeof(msg.msg) )
sz = sizeof(msg.msg);
if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
sz = WBUF_SIZE - WBUF_MASK(wc);
msg.type = CMSG_CONSOLE;
msg.subtype = CMSG_CONSOLE_DATA;
msg.length = sz;
memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
wc += sz;
}
}
/******************** User-space console driver (/dev/console) ************/
static struct termios *xencons_termios[MAX_NR_CONSOLES];
static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
static struct tty_struct *xencons_tty;
static int xencons_priv_irq;
static char x_char;
/* Non-privileged receive callback. */
static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
{
int i;
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
if ( xencons_tty != NULL )
{
for ( i = 0; i < msg->length; i++ )
tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
tty_flip_buffer_push(xencons_tty);
}
spin_unlock_irqrestore(&xencons_lock, flags);
msg->length = 0;
ctrl_if_send_response(msg);
}
/* Privileged and non-privileged transmit worker. */
static void __xencons_tx_flush(void)
{
int sz, work_done = 0;
ctrl_msg_t msg;
if ( start_info.flags & SIF_INITDOMAIN )
{
if ( x_char )
{
kcons_write_dom0(NULL, &x_char, 1);
x_char = 0;
work_done = 1;
}
while ( wc != wp )
{
sz = wp - wc;
if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
sz = WBUF_SIZE - WBUF_MASK(wc);
kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
wc += sz;
work_done = 1;
}
}
else
{
while ( x_char )
{
msg.type = CMSG_CONSOLE;
msg.subtype = CMSG_CONSOLE_DATA;
msg.length = 1;
msg.msg[0] = x_char;
if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
x_char = 0;
#if 0 /* XXXcl tq */
else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
#else
else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
#endif
break;
work_done = 1;
}
while ( wc != wp )
{
sz = wp - wc;
if ( sz > sizeof(msg.msg) )
sz = sizeof(msg.msg);
if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
sz = WBUF_SIZE - WBUF_MASK(wc);
msg.type = CMSG_CONSOLE;
msg.subtype = CMSG_CONSOLE_DATA;
msg.length = sz;
memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
wc += sz;
#if 0 /* XXXcl tq */
else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
#else
else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
#endif
break;
work_done = 1;
}
}
if ( work_done && (xencons_tty != NULL) )
{
wake_up_interruptible(&xencons_tty->write_wait);
if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
(xencons_tty->ldisc.write_wakeup != NULL) )
(xencons_tty->ldisc.write_wakeup)(xencons_tty);
}
}
/* Non-privileged transmit kicker. */
static void xencons_tx_flush_task_routine(void *data)
{
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
}
/* Privileged receive callback and transmit kicker. */
static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
static char rbuf[16];
int i, l;
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
if ( xencons_tty != NULL )
{
/* Receive work. */
while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
for ( i = 0; i < l; i++ )
tty_insert_flip_char(xencons_tty, rbuf[i], 0);
if ( xencons_tty->flip.count != 0 )
tty_flip_buffer_push(xencons_tty);
}
/* Transmit work. */
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
return IRQ_HANDLED;
}
static int xencons_write_room(struct tty_struct *tty)
{
return WBUF_SIZE - (wp - wc);
}
static int xencons_chars_in_buffer(struct tty_struct *tty)
{
return wp - wc;
}
static void xencons_send_xchar(struct tty_struct *tty, char ch)
{
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
x_char = ch;
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
}
static void xencons_throttle(struct tty_struct *tty)
{
if ( I_IXOFF(tty) )
xencons_send_xchar(tty, STOP_CHAR(tty));
}
static void xencons_unthrottle(struct tty_struct *tty)
{
if ( I_IXOFF(tty) )
{
if ( x_char != 0 )
x_char = 0;
else
xencons_send_xchar(tty, START_CHAR(tty));
}
}
static void xencons_flush_buffer(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
wc = wp = 0;
spin_unlock_irqrestore(&xencons_lock, flags);
}
static inline int __xencons_put_char(int ch)
{
char _ch = (char)ch;
if ( (wp - wc) == WBUF_SIZE )
return 0;
wbuf[WBUF_MASK(wp++)] = _ch;
return 1;
}
static int xencons_write(struct tty_struct *tty, int from_user,
const u_char * buf, int count)
{
int i;
unsigned long flags;
if ( from_user && verify_area(VERIFY_READ, buf, count) )
return -EINVAL;
spin_lock_irqsave(&xencons_lock, flags);
for ( i = 0; i < count; i++ )
{
char ch;
if ( from_user )
__get_user(ch, buf + i);
else
ch = buf[i];
if ( !__xencons_put_char(ch) )
break;
}
if ( i != 0 )
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
return i;
}
static void xencons_put_char(struct tty_struct *tty, u_char ch)
{
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
(void)__xencons_put_char(ch);
spin_unlock_irqrestore(&xencons_lock, flags);
}
static void xencons_flush_chars(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&xencons_lock, flags);
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
}
static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
{
unsigned long orig_jiffies = jiffies;
while ( tty->driver->chars_in_buffer(tty) )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
if ( signal_pending(current) )
break;
if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
break;
}
set_current_state(TASK_RUNNING);
}
static int xencons_open(struct tty_struct *tty, struct file *filp)
{
int line;
unsigned long flags;
MOD_INC_USE_COUNT;
line = tty->index;
if ( line < 0 || line >= NUM_XENCONS )
{
MOD_DEC_USE_COUNT;
return -ENODEV;
}
spin_lock_irqsave(&xencons_lock, flags);
tty->driver_data = NULL;
if ( xencons_tty == NULL )
xencons_tty = tty;
__xencons_tx_flush();
spin_unlock_irqrestore(&xencons_lock, flags);
return 0;
}
static void xencons_close(struct tty_struct *tty, struct file *filp)
{
unsigned long flags;
if ( tty->count == 1 )
{
tty->closing = 1;
tty_wait_until_sent(tty, 0);
if ( tty->driver->flush_buffer != NULL )
tty->driver->flush_buffer(tty);
if ( tty->ldisc.flush_buffer != NULL )
tty->ldisc.flush_buffer(tty);
tty->closing = 0;
spin_lock_irqsave(&xencons_lock, flags);
xencons_tty = NULL;
spin_unlock_irqrestore(&xencons_lock, flags);
}
MOD_DEC_USE_COUNT;
}
static struct tty_operations xencons_ops = {
.open = xencons_open,
.close = xencons_close,
.write = xencons_write,
.write_room = xencons_write_room,
.put_char = xencons_put_char,
.flush_chars = xencons_flush_chars,
.chars_in_buffer = xencons_chars_in_buffer,
.send_xchar = xencons_send_xchar,
.flush_buffer = xencons_flush_buffer,
.throttle = xencons_throttle,
.unthrottle = xencons_unthrottle,
.wait_until_sent = xencons_wait_until_sent,
};
static int __init xencons_init(void)
{
xencons_driver = alloc_tty_driver(NUM_XENCONS); /* XXX */
if (!xencons_driver)
return -ENOMEM;
xencons_driver->major = TTY_MAJOR;
xencons_driver->type = TTY_DRIVER_TYPE_SERIAL;
xencons_driver->subtype = SERIAL_TYPE_NORMAL;
xencons_driver->init_termios = tty_std_termios;
xencons_driver->flags =
TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
xencons_driver->termios = xencons_termios;
xencons_driver->termios_locked = xencons_termios_locked;
if ( xc_mode == XC_OFF )
return 0;
if ( xc_mode == XC_SERIAL )
{
xencons_driver->name = "ttyS";
xencons_driver->minor_start = 64;
xencons_driver->num = 1;
}
else
{
xencons_driver->name = "tty";
xencons_driver->minor_start = 1;
xencons_driver->num = MAX_NR_CONSOLES;
}
tty_set_operations(xencons_driver, &xencons_ops);
if ( tty_register_driver(xencons_driver) )
panic("Couldn't register Xen virtual console driver as %s\n",xencons_driver->name);
if ( start_info.flags & SIF_INITDOMAIN )
{
xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
(void)request_irq(xencons_priv_irq,
xencons_priv_interrupt, 0, "console", NULL);
}
else
{
(void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
}
printk("Xen virtual console successfully installed as %s\n",xencons_driver->name);
return 0;
}
static void __exit xencons_fini(void)
{
int ret;
if ( (ret = tty_unregister_driver(xencons_driver)) != 0 )
printk(KERN_ERR "Unable to unregister Xen console driver: %d\n", ret);
if ( start_info.flags & SIF_INITDOMAIN )
{
free_irq(xencons_priv_irq, NULL);
unbind_virq_from_irq(VIRQ_CONSOLE);
}
else
{
ctrl_if_unregister_receiver(CMSG_CONSOLE, xencons_rx);
}
}
module_init(xencons_init);
module_exit(xencons_fini);
@@ -0,0 +1,2 @@
obj-y := evtchn.o
@@ -0,0 +1,374 @@
/******************************************************************************
* evtchn.c
*
* Xenolinux driver for receiving and demuxing event-channel signals.
*
* Copyright (c) 2004, K A Fraser
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <asm-xen/evtchn.h>
#if 0
/* NB. This must be shared amongst drivers if more things go in /dev/xen */
static devfs_handle_t xen_dev_dir;
#endif
/* Only one process may open /dev/xen/evtchn at any time. */
static unsigned long evtchn_dev_inuse;
/* Notification ring, accessed via /dev/xen/evtchn. */
#define RING_SIZE 2048 /* 2048 16-bit entries */
#define RING_MASK(_i) ((_i)&(RING_SIZE-1))
static u16 *ring;
static unsigned int ring_cons, ring_prod, ring_overflow;
/* Processes wait on this queue via /dev/xen/evtchn when ring is empty. */
static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
static struct fasync_struct *evtchn_async_queue;
/* Which ports is user-space bound to? */
static u32 bound_ports[32];
static spinlock_t lock;
void evtchn_device_upcall(int port)
{
spin_lock(&lock);
mask_evtchn(port);
clear_evtchn(port);
if ( ring != NULL )
{
if ( (ring_prod - ring_cons) < RING_SIZE )
{
ring[RING_MASK(ring_prod)] = (u16)port;
if ( ring_cons == ring_prod++ )
{
wake_up_interruptible(&evtchn_wait);
kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
}
}
else
{
ring_overflow = 1;
}
}
spin_unlock(&lock);
}
static void __evtchn_reset_buffer_ring(void)
{
/* Initialise the ring to empty. Clear errors. */
ring_cons = ring_prod = ring_overflow = 0;
}
static ssize_t evtchn_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
int rc;
unsigned int c, p, bytes1 = 0, bytes2 = 0;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&evtchn_wait, &wait);
count &= ~1; /* even number of bytes */
if ( count == 0 )
{
rc = 0;
goto out;
}
if ( count > PAGE_SIZE )
count = PAGE_SIZE;
for ( ; ; )
{
set_current_state(TASK_INTERRUPTIBLE);
if ( (c = ring_cons) != (p = ring_prod) )
break;
if ( ring_overflow )
{
rc = -EFBIG;
goto out;
}
if ( file->f_flags & O_NONBLOCK )
{
rc = -EAGAIN;
goto out;
}
if ( signal_pending(current) )
{
rc = -ERESTARTSYS;
goto out;
}
schedule();
}
/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
if ( ((c ^ p) & RING_SIZE) != 0 )
{
bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
bytes2 = RING_MASK(p) * sizeof(u16);
}
else
{
bytes1 = (p - c) * sizeof(u16);
bytes2 = 0;
}
/* Truncate chunks according to caller's maximum byte count. */
if ( bytes1 > count )
{
bytes1 = count;
bytes2 = 0;
}
else if ( (bytes1 + bytes2) > count )
{
bytes2 = count - bytes1;
}
if ( copy_to_user(buf, &ring[RING_MASK(c)], bytes1) ||
((bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2)) )
{
rc = -EFAULT;
goto out;
}
ring_cons += (bytes1 + bytes2) / sizeof(u16);
rc = bytes1 + bytes2;
out:
__set_current_state(TASK_RUNNING);
remove_wait_queue(&evtchn_wait, &wait);
return rc;
}
static ssize_t evtchn_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
int rc, i;
u16 *kbuf = (u16 *)__get_free_page(GFP_KERNEL);
if ( kbuf == NULL )
return -ENOMEM;
count &= ~1; /* even number of bytes */
if ( count == 0 )
{
rc = 0;
goto out;
}
if ( count > PAGE_SIZE )
count = PAGE_SIZE;
if ( copy_from_user(kbuf, buf, count) != 0 )
{
rc = -EFAULT;
goto out;
}
spin_lock_irq(&lock);
for ( i = 0; i < (count/2); i++ )
if ( test_bit(kbuf[i], (unsigned long *)&bound_ports[0]) )
unmask_evtchn(kbuf[i]);
spin_unlock_irq(&lock);
rc = count;
out:
free_page((unsigned long)kbuf);
return rc;
}
static int evtchn_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int rc = 0;
spin_lock_irq(&lock);
switch ( cmd )
{
case EVTCHN_RESET:
__evtchn_reset_buffer_ring();
break;
case EVTCHN_BIND:
if ( !test_and_set_bit(arg, (unsigned long *)&bound_ports[0]) )
unmask_evtchn(arg);
else
rc = -EINVAL;
break;
case EVTCHN_UNBIND:
if ( test_and_clear_bit(arg, (unsigned long *)&bound_ports[0]) )
mask_evtchn(arg);
else
rc = -EINVAL;
break;
default:
rc = -ENOSYS;
break;
}
spin_unlock_irq(&lock);
return rc;
}
static unsigned int evtchn_poll(struct file *file, poll_table *wait)
{
unsigned int mask = POLLOUT | POLLWRNORM;
poll_wait(file, &evtchn_wait, wait);
if ( ring_cons != ring_prod )
mask |= POLLIN | POLLRDNORM;
if ( ring_overflow )
mask = POLLERR;
return mask;
}
static int evtchn_fasync(int fd, struct file *filp, int on)
{
return fasync_helper(fd, filp, on, &evtchn_async_queue);
}
static int evtchn_open(struct inode *inode, struct file *filp)
{
u16 *_ring;
if ( test_and_set_bit(0, &evtchn_dev_inuse) )
return -EBUSY;
/* Allocate outside locked region so that we can use GFP_KERNEL. */
if ( (_ring = (u16 *)__get_free_page(GFP_KERNEL)) == NULL )
return -ENOMEM;
spin_lock_irq(&lock);
ring = _ring;
__evtchn_reset_buffer_ring();
spin_unlock_irq(&lock);
MOD_INC_USE_COUNT;
return 0;
}
static int evtchn_release(struct inode *inode, struct file *filp)
{
int i;
spin_lock_irq(&lock);
if ( ring != NULL )
{
free_page((unsigned long)ring);
ring = NULL;
}
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
if ( test_and_clear_bit(i, (unsigned long *)&bound_ports[0]) )
mask_evtchn(i);
spin_unlock_irq(&lock);
evtchn_dev_inuse = 0;
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations evtchn_fops = {
owner: THIS_MODULE,
read: evtchn_read,
write: evtchn_write,
ioctl: evtchn_ioctl,
poll: evtchn_poll,
fasync: evtchn_fasync,
open: evtchn_open,
release: evtchn_release
};
static struct miscdevice evtchn_miscdev = {
.minor = EVTCHN_MINOR,
.name = "evtchn",
.devfs_name = "misc/evtchn",
.fops = &evtchn_fops
};
static int __init evtchn_init(void)
{
#if 0
devfs_handle_t symlink_handle;
int err, pos;
char link_dest[64];
#endif
int err;
/* (DEVFS) create '/dev/misc/evtchn'. */
err = misc_register(&evtchn_miscdev);
if ( err != 0 )
{
printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
return err;
}
#if 0
/* (DEVFS) create directory '/dev/xen'. */
xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
/* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
pos = devfs_generate_path(evtchn_miscdev.devfs_handle,
&link_dest[3],
sizeof(link_dest) - 3);
if ( pos >= 0 )
strncpy(&link_dest[pos], "../", 3);
/* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
(void)devfs_mk_symlink(xen_dev_dir,
"evtchn",
DEVFS_FL_DEFAULT,
&link_dest[pos],
&symlink_handle,
NULL);
/* (DEVFS) automatically destroy the symlink with its destination. */
devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
#endif
printk("Event-channel device installed.\n");
return 0;
}
static void evtchn_cleanup(void)
{
misc_deregister(&evtchn_miscdev);
}
module_init(evtchn_init);
module_exit(evtchn_cleanup);
@@ -0,0 +1,6 @@
config XENNET
tristate "Xen network driver"
depends on NETDEVICES && ARCH_XEN
help
Network driver for Xen
@@ -0,0 +1,2 @@
obj-y := network.o
@@ -0,0 +1,869 @@
/******************************************************************************
* network.c
*
* Virtual network driver for conversing with remote driver backends.
*
* Copyright (c) 2002-2004, K A Fraser
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <asm/io.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <asm-xen/evtchn.h>
#include <asm-xen/ctrl_if.h>
#include <asm/page.h>
#include <asm-xen/netif.h>
#define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */
static void network_tx_buf_gc(struct net_device *dev);
static void network_alloc_rx_buffers(struct net_device *dev);
static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE];
static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1];
static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
static struct list_head dev_list;
struct net_private
{
struct list_head list;
struct net_device *dev;
struct net_device_stats stats;
NETIF_RING_IDX rx_resp_cons, tx_resp_cons;
unsigned int tx_full;
netif_tx_interface_t *tx;
netif_rx_interface_t *rx;
spinlock_t tx_lock;
spinlock_t rx_lock;
unsigned int handle;
unsigned int evtchn;
unsigned int irq;
/* What is the status of our connection to the remote backend? */
#define BEST_CLOSED 0
#define BEST_DISCONNECTED 1
#define BEST_CONNECTED 2
unsigned int backend_state;
/* Is this interface open or closed (down or up)? */
#define UST_CLOSED 0
#define UST_OPEN 1
unsigned int user_state;
/*
* {tx,rx}_skbs store outstanding skbuffs. The first entry in each
* array is an index into a chain of free entries.
*/
struct sk_buff *tx_skbs[NETIF_TX_RING_SIZE+1];
struct sk_buff *rx_skbs[NETIF_RX_RING_SIZE+1];
};
/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
#define ADD_ID_TO_FREELIST(_list, _id) \
(_list)[(_id)] = (_list)[0]; \
(_list)[0] = (void *)(unsigned long)(_id);
#define GET_ID_FROM_FREELIST(_list) \
({ unsigned long _id = (unsigned long)(_list)[0]; \
(_list)[0] = (_list)[_id]; \
(unsigned short)_id; })
static struct net_device *find_dev_by_handle(unsigned int handle)
{
struct list_head *ent;
struct net_private *np;
list_for_each ( ent, &dev_list )
{
np = list_entry(ent, struct net_private, list);
if ( np->handle == handle )
return np->dev;
}
return NULL;
}
/** Network interface info. */
struct netif_ctrl {
/** Number of interfaces. */
int interface_n;
/** Number of connected interfaces. */
int connected_n;
/** Error code. */
int err;
};
static struct netif_ctrl netctrl;
static void netctrl_init(void)
{
memset(&netctrl, 0, sizeof(netctrl));
netctrl.interface_n = -1;
}
/** Get or set a network interface error.
*/
static int netctrl_err(int err)
{
if(err < 0 && !netctrl.err){
netctrl.err = err;
printk(KERN_WARNING "%s> err=%d\n", __FUNCTION__, err);
}
return netctrl.err;
}
/** Test if all network interfaces are connected.
*
* @return 1 if all connected, 0 if not, negative error code otherwise
*/
static int netctrl_connected(void)
{
int ok = 0;
ok = (netctrl.err ? netctrl.err :
(netctrl.connected_n == netctrl.interface_n));
return ok;
}
/** Count the connected network interfaces.
*
* @return connected count
*/
static int netctrl_connected_count(void)
{
struct list_head *ent;
struct net_private *np;
unsigned int connected;
connected = 0;
list_for_each(ent, &dev_list)
{
np = list_entry(ent, struct net_private, list);
if ( np->backend_state == BEST_CONNECTED )
connected++;
}
netctrl.connected_n = connected;
return connected;
}
static int network_open(struct net_device *dev)
{
struct net_private *np = dev->priv;
memset(&np->stats, 0, sizeof(np->stats));
np->user_state = UST_OPEN;
network_alloc_rx_buffers(dev);
np->rx->event = np->rx_resp_cons + 1;
netif_start_queue(dev);
return 0;
}
static void network_tx_buf_gc(struct net_device *dev)
{
NETIF_RING_IDX i, prod;
unsigned short id;
struct net_private *np = dev->priv;
struct sk_buff *skb;
if ( np->backend_state != BEST_CONNECTED )
return;
do {
prod = np->tx->resp_prod;
for ( i = np->tx_resp_cons; i != prod; i++ )
{
id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id;
skb = np->tx_skbs[id];
ADD_ID_TO_FREELIST(np->tx_skbs, id);
dev_kfree_skb_any(skb);
}
np->tx_resp_cons = prod;
/*
* Set a new event, then check for race with update of tx_cons. Note
* that it is essential to schedule a callback, no matter how few
* buffers are pending. Even if there is space in the transmit ring,
* higher layers may be blocked because too much data is outstanding:
* in such cases notification from Xen is likely to be the only kick
* that we'll get.
*/
np->tx->event =
prod + ((np->tx->req_prod - prod) >> 1) + 1;
mb();
}
while ( prod != np->tx->resp_prod );
if ( np->tx_full &&
((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE) )
{
np->tx_full = 0;
if ( np->user_state == UST_OPEN )
netif_wake_queue(dev);
}
}
static void network_alloc_rx_buffers(struct net_device *dev)
{
unsigned short id;
struct net_private *np = dev->priv;
struct sk_buff *skb;
NETIF_RING_IDX i = np->rx->req_prod;
int nr_pfns = 0;
/* Make sure the batch is large enough to be worthwhile (1/2 ring). */
if ( unlikely((i - np->rx_resp_cons) > (NETIF_RX_RING_SIZE/2)) ||
unlikely(np->backend_state != BEST_CONNECTED) )
return;
do {
skb = dev_alloc_skb(RX_BUF_SIZE);
if ( unlikely(skb == NULL) )
break;
skb->dev = dev;
if ( unlikely(((unsigned long)skb->head & (PAGE_SIZE-1)) != 0) )
panic("alloc_skb needs to provide us page-aligned buffers.");
id = GET_ID_FROM_FREELIST(np->rx_skbs);
np->rx_skbs[id] = skb;
np->rx->ring[MASK_NETIF_RX_IDX(i)].req.id = id;
rx_pfn_array[nr_pfns] = virt_to_machine(skb->head) >> PAGE_SHIFT;
rx_mcl[nr_pfns].op = __HYPERVISOR_update_va_mapping;
rx_mcl[nr_pfns].args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
rx_mcl[nr_pfns].args[1] = 0;
rx_mcl[nr_pfns].args[2] = 0;
nr_pfns++;
}
while ( (++i - np->rx_resp_cons) != NETIF_RX_RING_SIZE );
/*
* We may have allocated buffers which have entries outstanding in the page
* update queue -- make sure we flush those first!
*/
flush_page_update_queue();
/* After all PTEs have been zapped we blow away stale TLB entries. */
rx_mcl[nr_pfns-1].args[2] = UVMF_FLUSH_TLB;
/* Give away a batch of pages. */
rx_mcl[nr_pfns].op = __HYPERVISOR_dom_mem_op;
rx_mcl[nr_pfns].args[0] = MEMOP_decrease_reservation;
rx_mcl[nr_pfns].args[1] = (unsigned long)rx_pfn_array;
rx_mcl[nr_pfns].args[2] = (unsigned long)nr_pfns;
/* Zap PTEs and give away pages in one big multicall. */
(void)HYPERVISOR_multicall(rx_mcl, nr_pfns+1);
/* Check return status of HYPERVISOR_dom_mem_op(). */
if ( rx_mcl[nr_pfns].args[5] != nr_pfns )
panic("Unable to reduce memory reservation\n");
np->rx->req_prod = i;
}
static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned short id;
struct net_private *np = (struct net_private *)dev->priv;
netif_tx_request_t *tx;
NETIF_RING_IDX i;
if ( unlikely(np->tx_full) )
{
printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name);
netif_stop_queue(dev);
return -ENOBUFS;
}
if ( unlikely((((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >=
PAGE_SIZE) )
{
struct sk_buff *new_skb = dev_alloc_skb(RX_BUF_SIZE);
if ( unlikely(new_skb == NULL) )
return 1;
skb_put(new_skb, skb->len);
memcpy(new_skb->data, skb->data, skb->len);
dev_kfree_skb(skb);
skb = new_skb;
}
spin_lock_irq(&np->tx_lock);
if ( np->backend_state != BEST_CONNECTED )
{
spin_unlock_irq(&np->tx_lock);
return 1;
}
i = np->tx->req_prod;
id = GET_ID_FROM_FREELIST(np->tx_skbs);
np->tx_skbs[id] = skb;
tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req;
tx->id = id;
tx->addr = virt_to_machine(skb->data);
tx->size = skb->len;
wmb();
np->tx->req_prod = i + 1;
network_tx_buf_gc(dev);
if ( (i - np->tx_resp_cons) == (NETIF_TX_RING_SIZE - 1) )
{
np->tx_full = 1;
netif_stop_queue(dev);
}
spin_unlock_irq(&np->tx_lock);
np->stats.tx_bytes += skb->len;
np->stats.tx_packets++;
/* Only notify Xen if there are no outstanding responses. */
mb();
if ( np->tx->resp_prod == i )
notify_via_evtchn(np->evtchn);
return 0;
}
static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct net_device *dev = dev_id;
struct net_private *np = dev->priv;
unsigned long flags;
spin_lock_irqsave(&np->tx_lock, flags);
network_tx_buf_gc(dev);
spin_unlock_irqrestore(&np->tx_lock, flags);
if ( (np->rx_resp_cons != np->rx->resp_prod) &&
(np->user_state == UST_OPEN) )
netif_rx_schedule(dev);
return IRQ_HANDLED;
}
static int netif_poll(struct net_device *dev, int *pbudget)
{
struct net_private *np = dev->priv;
struct sk_buff *skb;
netif_rx_response_t *rx;
NETIF_RING_IDX i;
mmu_update_t *mmu = rx_mmu;
multicall_entry_t *mcl = rx_mcl;
int work_done, budget, more_to_do = 1;
struct sk_buff_head rxq;
unsigned long flags;
spin_lock(&np->rx_lock);
if ( np->backend_state != BEST_CONNECTED )
{
spin_unlock(&np->rx_lock);
return 0;
}
skb_queue_head_init(&rxq);
if ( (budget = *pbudget) > dev->quota )
budget = dev->quota;
for ( i = np->rx_resp_cons, work_done = 0;
(i != np->rx->resp_prod) && (work_done < budget);
i++, work_done++ )
{
rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp;
skb = np->rx_skbs[rx->id];
ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
if ( unlikely(rx->status <= 0) )
{
/* Gate this error. We get a (valid) slew of them on suspend. */
if ( np->user_state != UST_OPEN )
printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
dev_kfree_skb(skb);
continue;
}
skb->data = skb->tail = skb->head + (rx->addr & ~PAGE_MASK);
skb_put(skb, rx->status);
np->stats.rx_packets++;
np->stats.rx_bytes += rx->status;
/* Remap the page. */
mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE;
mmu->val = __pa(skb->head) >> PAGE_SHIFT;
mmu++;
mcl->op = __HYPERVISOR_update_va_mapping;
mcl->args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL;
mcl->args[2] = 0;
mcl++;
phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] =
rx->addr >> PAGE_SHIFT;
__skb_queue_tail(&rxq, skb);
}
/* Do all the remapping work, and M->P updates, in one big hypercall. */
if ( likely((mcl - rx_mcl) != 0) )
{
mcl->op = __HYPERVISOR_mmu_update;
mcl->args[0] = (unsigned long)rx_mmu;
mcl->args[1] = mmu - rx_mmu;
mcl->args[2] = 0;
mcl++;
(void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
}
while ( (skb = __skb_dequeue(&rxq)) != NULL )
{
/* Set the shared-info area, which is hidden behind the real data. */
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
/* Ethernet-specific work. Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
/* Pass it up. */
netif_rx(skb);
dev->last_rx = jiffies;
}
np->rx_resp_cons = i;
network_alloc_rx_buffers(dev);
*pbudget -= work_done;
dev->quota -= work_done;
if ( work_done < budget )
{
local_irq_save(flags);
np->rx->event = i + 1;
/* Deal with hypervisor racing our resetting of rx_event. */
mb();
if ( np->rx->resp_prod == i )
{
__netif_rx_complete(dev);
more_to_do = 0;
}
local_irq_restore(flags);
}
spin_unlock(&np->rx_lock);
return more_to_do;
}
static int network_close(struct net_device *dev)
{
struct net_private *np = dev->priv;
np->user_state = UST_CLOSED;
netif_stop_queue(np->dev);
return 0;
}
static struct net_device_stats *network_get_stats(struct net_device *dev)
{
struct net_private *np = (struct net_private *)dev->priv;
return &np->stats;
}
static void network_connect(struct net_device *dev,
netif_fe_interface_status_changed_t *status)
{
struct net_private *np;
int i, requeue_idx;
netif_tx_request_t *tx;
np = dev->priv;
spin_lock_irq(&np->rx_lock);
spin_lock(&np->tx_lock);
/* Recovery procedure: */
/* Step 1: Reinitialise variables. */
np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
np->rx->event = 1;
/* Step 2: Rebuild the RX and TX ring contents.
* NB. We could just free the queued TX packets now but we hope
* that sending them out might do some good. We have to rebuild
* the RX ring because some of our pages are currently flipped out
* so we can't just free the RX skbs.
* NB2. Freelist index entries are always going to be less than
* __PAGE_OFFSET, whereas pointers to skbs will always be equal or
* greater than __PAGE_OFFSET: we use this property to distinguish
* them.
*/
/* Rebuild the TX buffer freelist and the TX ring itself.
* NB. This reorders packets. We could keep more private state
* to avoid this but maybe it doesn't matter so much given the
* interface has been down.
*/
for ( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ )
{
if ( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET )
{
struct sk_buff *skb = np->tx_skbs[i];
tx = &np->tx->ring[requeue_idx++].req;
tx->id = i;
tx->addr = virt_to_machine(skb->data);
tx->size = skb->len;
np->stats.tx_bytes += skb->len;
np->stats.tx_packets++;
}
}
wmb();
np->tx->req_prod = requeue_idx;
/* Rebuild the RX buffer freelist and the RX ring itself. */
for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ )
if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET )
np->rx->ring[requeue_idx++].req.id = i;
wmb();
np->rx->req_prod = requeue_idx;
/* Step 3: All public and private state should now be sane. Get
* ready to start sending and receiving packets and give the driver
* domain a kick because we've probably just requeued some
* packets.
*/
np->backend_state = BEST_CONNECTED;
notify_via_evtchn(status->evtchn);
network_tx_buf_gc(dev);
if ( np->user_state == UST_OPEN )
netif_start_queue(dev);
spin_unlock(&np->tx_lock);
spin_unlock_irq(&np->rx_lock);
}
static void netif_status_change(netif_fe_interface_status_changed_t *status)
{
ctrl_msg_t cmsg;
netif_fe_interface_connect_t up;
struct net_device *dev;
struct net_private *np;
if ( netctrl.interface_n <= 0 )
{
printk(KERN_WARNING "Status change: no interfaces\n");
return;
}
dev = find_dev_by_handle(status->handle);
if(!dev){
printk(KERN_WARNING "Status change: invalid netif handle %u\n",
status->handle);
return;
}
np = dev->priv;
switch ( status->status )
{
case NETIF_INTERFACE_STATUS_DESTROYED:
printk(KERN_WARNING "Unexpected netif-DESTROYED message in state %d\n",
np->backend_state);
break;
case NETIF_INTERFACE_STATUS_DISCONNECTED:
if ( np->backend_state != BEST_CLOSED )
{
printk(KERN_WARNING "Unexpected netif-DISCONNECTED message"
" in state %d\n", np->backend_state);
printk(KERN_INFO "Attempting to reconnect network interface\n");
/* Begin interface recovery.
*
* NB. Whilst we're recovering, we turn the carrier state off. We
* take measures to ensure that this device isn't used for
* anything. We also stop the queue for this device. Various
* different approaches (e.g. continuing to buffer packets) have
* been tested but don't appear to improve the overall impact on
* TCP connections.
*
* TODO: (MAW) Change the Xend<->Guest protocol so that a recovery
* is initiated by a special "RESET" message - disconnect could
* just mean we're not allowed to use this interface any more.
*/
/* Stop old i/f to prevent errors whilst we rebuild the state. */
spin_lock_irq(&np->tx_lock);
spin_lock(&np->rx_lock);
netif_stop_queue(dev);
np->backend_state = BEST_DISCONNECTED;
spin_unlock(&np->rx_lock);
spin_unlock_irq(&np->tx_lock);
/* Free resources. */
free_irq(np->irq, dev);
unbind_evtchn_from_irq(np->evtchn);
free_page((unsigned long)np->tx);
free_page((unsigned long)np->rx);
}
/* Move from CLOSED to DISCONNECTED state. */
np->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL);
np->rx = (netif_rx_interface_t *)__get_free_page(GFP_KERNEL);
memset(np->tx, 0, PAGE_SIZE);
memset(np->rx, 0, PAGE_SIZE);
np->backend_state = BEST_DISCONNECTED;
/* Construct an interface-CONNECT message for the domain controller. */
cmsg.type = CMSG_NETIF_FE;
cmsg.subtype = CMSG_NETIF_FE_INTERFACE_CONNECT;
cmsg.length = sizeof(netif_fe_interface_connect_t);
up.handle = status->handle;
up.tx_shmem_frame = virt_to_machine(np->tx) >> PAGE_SHIFT;
up.rx_shmem_frame = virt_to_machine(np->rx) >> PAGE_SHIFT;
memcpy(cmsg.msg, &up, sizeof(up));
/* Tell the controller to bring up the interface. */
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
break;
case NETIF_INTERFACE_STATUS_CONNECTED:
if ( np->backend_state == BEST_CLOSED )
{
printk(KERN_WARNING "Unexpected netif-CONNECTED message"
" in state %d\n", np->backend_state);
break;
}
memcpy(dev->dev_addr, status->mac, ETH_ALEN);
network_connect(dev, status);
np->evtchn = status->evtchn;
np->irq = bind_evtchn_to_irq(np->evtchn);
(void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM,
dev->name, dev);
netctrl_connected_count();
break;
default:
printk(KERN_WARNING "Status change to unknown value %d\n",
status->status);
break;
}
}
/** Create a network device.
* @param handle device handle
* @param val return parameter for created device
* @return 0 on success, error code otherwise
*/
static int create_netdev(int handle, struct net_device **val)
{
int i, err = 0;
struct net_device *dev = NULL;
struct net_private *np = NULL;
if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL )
{
printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__);
err = -ENOMEM;
goto exit;
}
np = dev->priv;
np->backend_state = BEST_CLOSED;
np->user_state = UST_CLOSED;
np->handle = handle;
spin_lock_init(&np->tx_lock);
spin_lock_init(&np->rx_lock);
/* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
for ( i = 0; i <= NETIF_TX_RING_SIZE; i++ )
np->tx_skbs[i] = (void *)(i+1);
for ( i = 0; i <= NETIF_RX_RING_SIZE; i++ )
np->rx_skbs[i] = (void *)(i+1);
dev->open = network_open;
dev->hard_start_xmit = network_start_xmit;
dev->stop = network_close;
dev->get_stats = network_get_stats;
dev->poll = netif_poll;
dev->weight = 64;
if ( (err = register_netdev(dev)) != 0 )
{
printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err);
goto exit;
}
np->dev = dev;
list_add(&np->list, &dev_list);
exit:
if ( (err != 0) && (dev != NULL ) )
kfree(dev);
else if ( val != NULL )
*val = dev;
return err;
}
/*
* Initialize the network control interface. Set the number of network devices
* and create them.
*/
static void netif_driver_status_change(
netif_fe_driver_status_changed_t *status)
{
int err = 0;
int i;
netctrl.interface_n = status->nr_interfaces;
netctrl.connected_n = 0;
for ( i = 0; i < netctrl.interface_n; i++ )
{
if ( (err = create_netdev(i, NULL)) != 0 )
{
netctrl_err(err);
break;
}
}
}
static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
{
int respond = 1;
switch ( msg->subtype )
{
case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
if ( msg->length != sizeof(netif_fe_interface_status_changed_t) )
goto error;
netif_status_change((netif_fe_interface_status_changed_t *)
&msg->msg[0]);
break;
case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
if ( msg->length != sizeof(netif_fe_driver_status_changed_t) )
goto error;
netif_driver_status_change((netif_fe_driver_status_changed_t *)
&msg->msg[0]);
/* Message is a response */
respond = 0;
break;
error:
default:
msg->length = 0;
break;
}
if ( respond )
ctrl_if_send_response(msg);
}
static int __init netif_init(void)
{
ctrl_msg_t cmsg;
netif_fe_driver_status_changed_t st;
int err = 0, wait_i, wait_n = 20;
if ( (start_info.flags & SIF_INITDOMAIN) ||
(start_info.flags & SIF_NET_BE_DOMAIN) )
return 0;
printk("Initialising Xen virtual ethernet frontend driver");
INIT_LIST_HEAD(&dev_list);
netctrl_init();
(void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
/* Send a driver-UP notification to the domain controller. */
cmsg.type = CMSG_NETIF_FE;
cmsg.subtype = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED;
cmsg.length = sizeof(netif_fe_driver_status_changed_t);
st.status = NETIF_DRIVER_STATUS_UP;
st.nr_interfaces = 0;
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
/* Wait for all interfaces to be connected. */
for ( wait_i = 0; ; wait_i++)
{
if ( (err = (wait_i < wait_n) ? netctrl_connected() : -ENETDOWN) != 0 )
{
err = (err > 0) ? 0 : err;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
if ( err )
ctrl_if_unregister_receiver(CMSG_NETIF_FE, netif_ctrlif_rx);
return err;
}
__initcall(netif_init);
@@ -0,0 +1,133 @@
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
#include <asm/ldt.h>
#include <asm/segment.h>
#ifndef __ASSEMBLY__
#include <linux/preempt.h>
#include <linux/smp.h>
#include <asm/mmu.h>
extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES];
struct Xgt_desc_struct {
unsigned short size;
unsigned long address __attribute__((packed));
unsigned short pad;
} __attribute__ ((packed));
extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
#define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
#define get_cpu_gdt_table(_cpu) ((struct desc_struct *)cpu_gdt_descr[(_cpu)].address)
/*
* This is the ldt that every process will get unless we need
* something other than this.
*/
extern struct desc_struct default_ldt[];
extern void set_intr_gate(unsigned int irq, void * addr);
#define _set_tssldt_desc(n,addr,limit,type) \
__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
"movw %%ax,2(%2)\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,4(%2)\n\t" \
"movb %4,5(%2)\n\t" \
"movb $0,6(%2)\n\t" \
"movb %%ah,7(%2)\n\t" \
"rorl $16,%%eax" \
: "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
{
_set_tssldt_desc(&get_cpu_gdt_table(cpu)[entry],
(int)addr, 235, 0x89);
}
#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
{
_set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT],
(int)addr, ((size << 3)-1), 0x82);
}
#define LDT_entry_a(info) \
((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
#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) | \
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 )
#if TLS_SIZE != 24
# error update this code.
#endif
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), ((u32 *)&t->tls_array[i])[0], ((u32 *)&t->tls_array[i])[1])
C(0); C(1); C(2);
#undef C
}
static inline void clear_LDT(void)
{
int cpu = get_cpu();
/*
* NB. We load the default_ldt for lcall7/27 handling on demand, as
* it slows down context switching. Noone uses it anyway.
*/
cpu = cpu; /* XXX avoid compiler warning */
queue_set_ldt(0UL, 0);
put_cpu();
}
/*
* load one particular LDT into the current CPU
*/
static 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();
}
#endif /* !__ASSEMBLY__ */
#endif
@@ -0,0 +1,40 @@
/*
* structures and definitions for the int 15, ax=e820 memory map
* scheme.
*
* In a nutshell, arch/i386/boot/setup.S populates a scratch table
* in the empty_zero_block that contains a list of usable address/size
* duples. In arch/i386/kernel/setup.c, this information is
* transferred into the e820map, and in arch/i386/mm/init.c, that
* new information is used to mark pages reserved or not.
*
*/
#ifndef __E820_HEADER
#define __E820_HEADER
#define E820MAP 0x2d0 /* our map */
#define E820MAX 32 /* number of entries in E820MAP */
#define E820NR 0x1e8 /* # entries in E820MAP */
#define E820_RAM 1
#define E820_RESERVED 2
#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
#define E820_NVS 4
#define HIGH_MEMORY (0)
#ifndef __ASSEMBLY__
struct e820map {
int nr_map;
struct e820entry {
unsigned long long addr; /* start of memory segment */
unsigned long long size; /* size of memory segment */
unsigned long type; /* type of memory segment */
} map[E820MAX];
};
extern struct e820map e820;
#endif/*!__ASSEMBLY__*/
#endif/*__E820_HEADER*/
@@ -0,0 +1,156 @@
/*
* 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
*
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
*/
#ifndef _ASM_FIXMAP_H
#define _ASM_FIXMAP_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/acpi.h>
#include <asm/apicdef.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
/*
* 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. We allocate these special addresses
* from the end of virtual memory (0xfffff000) backwards.
* Also this lets us do fail-safe vmalloc(), we
* can guarantee that these special addresses and
* vmalloc()-ed addresses never overlap.
*
* 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 {
FIX_HOLE,
FIX_VSYSCALL,
#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
#ifdef CONFIG_X86_VISWS_APIC
FIX_CO_CPU, /* Cobalt timer */
FIX_CO_APIC, /* Cobalt APIC Redirection Table */
FIX_LI_PCIA, /* Lithium PCI Bridge A */
FIX_LI_PCIB, /* Lithium PCI Bridge B */
#endif
#ifdef CONFIG_X86_F00F_BUG
FIX_F00F_IDT, /* Virtual mapping for IDT */
#endif
#ifdef CONFIG_X86_CYCLONE_TIMER
FIX_CYCLONE_TIMER, /*cyclone timer register*/
#endif
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
#ifdef CONFIG_ACPI_BOOT
FIX_ACPI_BEGIN,
FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
#endif
#ifdef CONFIG_PCI_MMCONFIG
FIX_PCIE_MCFG,
#endif
FIX_SHARED_INFO,
__end_of_permanent_fixed_addresses,
/* temporary boot-time mappings, used before ioremap() is functional */
#define NR_FIX_BTMAPS 16
FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
FIX_WP_TEST,
__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)
/*
* 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))
/*
* used by vmalloc.c.
*
* Leave one empty page between vmalloc'ed areas and
* the start of the fixmap.
*/
#define FIXADDR_TOP (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE)
#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
/*
* This is the range that is readable by user mode, and things
* acting like user mode such as get_user_pages.
*/
#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL))
#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
extern void __this_fixmap_does_not_exist(void);
/*
* 'index to address' translation. If anyone tries to use the idx
* directly without tranlation, we catch the bug with a NULL-deference
* kernel oops. Illegal ranges of incoming indices are caught too.
*/
static 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);
}
static inline unsigned long virt_to_fix(const unsigned long vaddr)
{
BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
return __virt_to_fix(vaddr);
}
#endif
@@ -0,0 +1,455 @@
/******************************************************************************
* hypervisor.h
*
* Linux-specific hypervisor handling.
*
* Copyright (c) 2002, K A Fraser
*/
#ifndef __HYPERVISOR_H__
#define __HYPERVISOR_H__
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/hypervisor-ifs/hypervisor-if.h>
#include <asm/hypervisor-ifs/dom0_ops.h>
#include <asm-xen/domain_controller.h>
#include <asm/ptrace.h>
#include <asm/page.h>
#include <asm-xen/xen.h>
/* arch/xen/i386/kernel/setup.c */
union start_info_union
{
extended_start_info_t start_info;
char padding[512];
};
extern union start_info_union start_info_union;
#define start_info (start_info_union.start_info)
/* arch/xen/i386/kernel/hypervisor.c */
void do_hypervisor_callback(struct pt_regs *regs);
/* arch/xen/i386/mm/init.c */
void wrprotect_bootpt(pgd_t *, void *, int);
/* arch/xen/i386/kernel/head.S */
void lgdt_finish(void);
/* arch/xen/i386/mm/hypervisor.c */
/*
* NB. ptr values should be PHYSICAL, not MACHINE. 'vals' should be already
* be MACHINE addresses.
*/
extern unsigned int mmu_update_queue_idx;
void queue_l1_entry_update(pte_t *ptr, unsigned long val);
void queue_l2_entry_update(pmd_t *ptr, unsigned long val);
void queue_pt_switch(unsigned long ptr);
void queue_tlb_flush(void);
void queue_invlpg(unsigned long ptr);
void queue_pgd_pin(unsigned long ptr);
void queue_pgd_unpin(unsigned long ptr);
void queue_pte_pin(unsigned long ptr);
void queue_pte_unpin(unsigned long ptr);
void queue_set_ldt(unsigned long ptr, unsigned long bytes);
void queue_machphys_update(unsigned long mfn, unsigned long pfn);
#define MMU_UPDATE_DEBUG 0
#if MMU_UPDATE_DEBUG > 0
typedef struct {
void *ptr;
unsigned long val, pteval;
void *ptep;
int line; char *file;
} page_update_debug_t;
extern page_update_debug_t update_debug_queue[];
#define queue_l1_entry_update(_p,_v) ({ \
update_debug_queue[mmu_update_queue_idx].ptr = (_p); \
update_debug_queue[mmu_update_queue_idx].val = (_v); \
update_debug_queue[mmu_update_queue_idx].line = __LINE__; \
update_debug_queue[mmu_update_queue_idx].file = __FILE__; \
queue_l1_entry_update((_p),(_v)); \
})
#define queue_l2_entry_update(_p,_v) ({ \
update_debug_queue[mmu_update_queue_idx].ptr = (_p); \
update_debug_queue[mmu_update_queue_idx].val = (_v); \
update_debug_queue[mmu_update_queue_idx].line = __LINE__; \
update_debug_queue[mmu_update_queue_idx].file = __FILE__; \
queue_l2_entry_update((_p),(_v)); \
})
#endif
#if MMU_UPDATE_DEBUG > 1
#if MMU_UPDATE_DEBUG > 2
#undef queue_l1_entry_update
#define queue_l1_entry_update(_p,_v) ({ \
update_debug_queue[mmu_update_queue_idx].ptr = (_p); \
update_debug_queue[mmu_update_queue_idx].val = (_v); \
update_debug_queue[mmu_update_queue_idx].line = __LINE__; \
update_debug_queue[mmu_update_queue_idx].file = __FILE__; \
printk("L1 %s %d: %p/%08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
(_p), virt_to_machine(_p), pte_val(*(_p)), \
(unsigned long)(_v)); \
queue_l1_entry_update((_p),(_v)); \
})
#endif
#undef queue_l2_entry_update
#define queue_l2_entry_update(_p,_v) ({ \
update_debug_queue[mmu_update_queue_idx].ptr = (_p); \
update_debug_queue[mmu_update_queue_idx].val = (_v); \
update_debug_queue[mmu_update_queue_idx].line = __LINE__; \
update_debug_queue[mmu_update_queue_idx].file = __FILE__; \
printk("L2 %s %d: %p/%08lx (%08lx -> %08lx)\n", __FILE__, __LINE__, \
(_p), virt_to_machine(_p), pmd_val(*_p), \
(unsigned long)(_v)); \
queue_l2_entry_update((_p),(_v)); \
})
#define queue_pt_switch(_p) ({ \
printk("PTSWITCH %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_pt_switch(_p); \
})
#define queue_tlb_flush() ({ \
printk("TLB FLUSH %s %d\n", __FILE__, __LINE__); \
queue_tlb_flush(); \
})
#define queue_invlpg(_p) ({ \
printk("INVLPG %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_invlpg(_p); \
})
#define queue_pgd_pin(_p) ({ \
printk("PGD PIN %s %d: %08lx/%08lx\n", __FILE__, __LINE__, (_p), \
phys_to_machine(_p)); \
queue_pgd_pin(_p); \
})
#define queue_pgd_unpin(_p) ({ \
printk("PGD UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_pgd_unpin(_p); \
})
#define queue_pte_pin(_p) ({ \
printk("PTE PIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_pte_pin(_p); \
})
#define queue_pte_unpin(_p) ({ \
printk("PTE UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_pte_unpin(_p); \
})
#define queue_set_ldt(_p,_l) ({ \
printk("SETL LDT %s %d: %08lx %d\n", __FILE__, __LINE__, (_p), (_l)); \
queue_set_ldt((_p), (_l)); \
})
#endif
void _flush_page_update_queue(void);
static inline int flush_page_update_queue(void)
{
unsigned int idx = mmu_update_queue_idx;
if ( idx != 0 ) _flush_page_update_queue();
return idx;
}
#define xen_flush_page_update_queue() (_flush_page_update_queue())
void MULTICALL_flush_page_update_queue(void);
/*
* 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" (__HYPERVISOR_set_trap_table),
"b" (table) : "memory" );
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" (__HYPERVISOR_mmu_update),
"b" (req), "c" (count), "d" (success_count) : "memory" );
return ret;
}
static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
"b" (frame_list), "c" (entries) : "memory" );
return ret;
}
static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
"b" (ss), "c" (esp) : "memory" );
return ret;
}
static inline int HYPERVISOR_set_callbacks(
unsigned long event_selector, unsigned long event_address,
unsigned long failsafe_selector, unsigned long failsafe_address)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
"b" (event_selector), "c" (event_address),
"d" (failsafe_selector), "S" (failsafe_address) : "memory" );
return ret;
}
static inline int HYPERVISOR_fpu_taskswitch(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_fpu_taskswitch) : "memory" );
return ret;
}
static inline int HYPERVISOR_yield(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_yield) : "memory" );
return ret;
}
static inline int HYPERVISOR_block(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_block) : "memory" );
return ret;
}
static inline int HYPERVISOR_shutdown(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))
: "memory" );
return ret;
}
static inline int HYPERVISOR_reboot(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))
: "memory" );
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" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)),
"S" (srec) : "memory" );
return ret;
}
static inline long HYPERVISOR_set_timer_op(u64 timeout)
{
int ret;
unsigned long timeout_hi = (unsigned long)(timeout>>32);
unsigned long timeout_lo = (unsigned long)timeout;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_timer_op),
"b" (timeout_hi), "c" (timeout_lo) : "memory" );
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" (__HYPERVISOR_dom0_op),
"b" (dom0_op) : "memory" );
return ret;
}
static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_debugreg),
"b" (reg), "c" (value) : "memory" );
return ret;
}
static inline unsigned long HYPERVISOR_get_debugreg(int reg)
{
unsigned long ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_get_debugreg),
"b" (reg) : "memory" );
return ret;
}
static inline int HYPERVISOR_update_descriptor(
unsigned long ma, unsigned long word1, unsigned long word2)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_update_descriptor),
"b" (ma), "c" (word1), "d" (word2) : "memory" );
return ret;
}
static inline int HYPERVISOR_set_fast_trap(int idx)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_fast_trap),
"b" (idx) : "memory" );
return ret;
}
static inline int HYPERVISOR_dom_mem_op(unsigned int op,
unsigned long *pages,
unsigned long nr_pages)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_dom_mem_op),
"b" (op), "c" (pages), "d" (nr_pages) : "memory" );
return ret;
}
static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_multicall),
"b" (call_list), "c" (nr_calls) : "memory" );
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" (__HYPERVISOR_update_va_mapping),
"b" (page_nr), "c" ((new_val).pte_low), "d" (flags) : "memory" );
if ( unlikely(ret < 0) )
panic("Failed update VA mapping: %08lx, %08lx, %08lx",
page_nr, (new_val).pte_low, flags);
return ret;
}
static inline int HYPERVISOR_event_channel_op(void *op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_event_channel_op),
"b" (op) : "memory" );
return ret;
}
static inline int HYPERVISOR_xen_version(int cmd)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_xen_version),
"b" (cmd) : "memory" );
return ret;
}
static inline int HYPERVISOR_console_io(int cmd, int count, char *str)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_console_io),
"b" (cmd), "c" (count), "d" (str) : "memory" );
return ret;
}
static inline int HYPERVISOR_physdev_op(void *physdev_op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_physdev_op),
"b" (physdev_op) : "memory" );
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__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_update_va_mapping_otherdomain),
"b" (page_nr), "c" ((new_val).pte_low), "d" (flags), "S" (domid) :
"memory" );
return ret;
}
#endif /* __HYPERVISOR_H__ */
@@ -0,0 +1,367 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
#include <linux/config.h>
/*
* This file contains the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
* (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
* versions of the single-IO instructions (inb_p/inw_p/..).
*
* This file is not meant to be obfuscating: it's just complicated
* to (a) handle it all in a way that makes gcc able to optimize it
* as well as possible and (b) trying to avoid writing the same thing
* over and over again with slight variations and possibly making a
* mistake somewhere.
*/
/*
* Thanks to James van Artsdalen for a better timing-fix than
* the two short jumps: using outb's to a nonexistent port seems
* to guarantee better timings even on fast machines.
*
* On the other hand, I'd like to be sure of a non-existent port:
* I feel a bit unsafe about using 0x80 (should be safe, though)
*
* Linus
*/
/*
* Bit simplified and optimized by Jan Hubicka
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
*
* isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
* isa_read[wl] and isa_write[wl] fixed
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*/
#define IO_SPACE_LIMIT 0xffff
#define XQUAD_PORTIO_BASE 0xfe400000
#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
#ifdef __KERNEL__
#include <linux/vmalloc.h>
/**
* virt_to_phys - map virtual addresses to physical
* @address: address to remap
*
* The returned physical address is the physical (CPU) mapping for
* the memory address given. It is only valid to use this function on
* addresses directly mapped or allocated via kmalloc.
*
* This function does not give bus mappings for DMA transfers. In
* almost all conceivable cases a device driver should not be using
* this function
*/
static inline unsigned long virt_to_phys(volatile void * address)
{
return __pa(address);
}
/**
* phys_to_virt - map physical address to virtual
* @address: address to remap
*
* The returned virtual address is a current CPU mapping for
* the memory address given. It is only valid to use this function on
* addresses that have a kernel mapping
*
* This function does not handle bus mappings for DMA transfers. In
* almost all conceivable cases a device driver should not be using
* this function
*/
static inline void * phys_to_virt(unsigned long address)
{
return __va(address);
}
/*
* Change "struct page" to physical address.
*/
#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
/**
* ioremap - map bus memory into CPU space
* @offset: bus address of the memory
* @size: size of the resource to map
*
* ioremap performs a platform specific sequence of operations to
* make bus memory CPU accessible via the readb/readw/readl/writeb/
* writew/writel functions and the other mmio helpers. The returned
* address is not guaranteed to be usable directly as a virtual
* address.
*/
static inline void * ioremap (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, 0);
}
extern void * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap(void *addr);
/*
* bt_ioremap() and bt_iounmap() are for temporary early boot-time
* mappings, before the real ioremap() is functional.
* A boot-time mapping is currently limited to at most 16 pages.
*/
extern void *bt_ioremap(unsigned long offset, unsigned long size);
extern void bt_iounmap(void *addr, unsigned long size);
/*
* ISA I/O bus memory addresses are 1:1 with the physical address.
*/
#define isa_virt_to_bus(_x) phys_to_machine(virt_to_phys(_x))
#define isa_page_to_bus(_x) phys_to_machine(page_to_phys(_x))
#define isa_bus_to_virt(_x) phys_to_virt(machine_to_phys(_x))
/*
* However PCI ones are not necessarily 1:1 and therefore these interfaces
* are forbidden in portable PCI drivers.
*
* Allow them on x86 for legacy drivers, though.
*/
#define virt_to_bus(_x) phys_to_machine(virt_to_phys(_x))
#define bus_to_virt(_x) phys_to_virt(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.
*/
#define readb(addr) (*(volatile unsigned char *) (addr))
#define readw(addr) (*(volatile unsigned short *) (addr))
#define readl(addr) (*(volatile unsigned int *) (addr))
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) __memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) __memcpy((void *)(a),(b),(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 *)(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, i386 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(unsigned long 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;
}
/**
* isa_check_signature - find BIOS signatures
* @io_addr: mmio address to check
* @signature: signature block
* @length: length of signature
*
* Perform a signature comparison with the ISA mmio address io_addr.
* Returns 1 on a match.
*
* This function is deprecated. New drivers should use ioremap and
* check_signature.
*/
static inline int isa_check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
{
int retval = 0;
do {
if (isa_readb(io_addr) != *signature)
goto out;
io_addr++;
signature++;
length--;
} while (length);
retval = 1;
out:
return retval;
}
/*
* Cache management
*
* This needed for two cases
* 1. Out of order aware processors
* 2. Accidentally out of order processors (PPro errata #51)
*/
#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
static inline void flush_write_buffers(void)
{
__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
}
#define dma_cache_inv(_start,_size) flush_write_buffers()
#define dma_cache_wback(_start,_size) flush_write_buffers()
#define dma_cache_wback_inv(_start,_size) flush_write_buffers()
#else
/* Nothing to do */
#define dma_cache_inv(_start,_size) do { } while (0)
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
#define flush_write_buffers()
#endif
#endif /* __KERNEL__ */
#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO "jmp 1f; 1: jmp 1f; 1:"
#else
#define __SLOW_DOWN_IO "outb %%al,$0x80;"
#endif
static inline void slow_down_io(void) {
__asm__ __volatile__(
__SLOW_DOWN_IO
#ifdef REALLY_SLOW_IO
__SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
: : );
}
#ifdef CONFIG_X86_NUMAQ
extern void *xquad_portio; /* Where the IO area was mapped */
#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
#define __BUILDIO(bwl,bw,type) \
static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
if (xquad_portio) \
write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
else \
out##bwl##_local(value, port); \
} \
static inline void out##bwl(unsigned type value, int port) { \
out##bwl##_quad(value, port, 0); \
} \
static inline unsigned type in##bwl##_quad(int port, int quad) { \
if (xquad_portio) \
return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
else \
return in##bwl##_local(port); \
} \
static inline unsigned type in##bwl(int port) { \
return in##bwl##_quad(port, 0); \
}
#else
#define __BUILDIO(bwl,bw,type) \
static inline void out##bwl(unsigned type value, int port) { \
out##bwl##_local(value, port); \
} \
static inline unsigned type in##bwl(int port) { \
return in##bwl##_local(port); \
}
#endif
#define BUILDIO(bwl,bw,type) \
static inline void out##bwl##_local(unsigned type value, int port) { \
__asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \
} \
static inline unsigned type in##bwl##_local(int port) { \
unsigned type value; \
__asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \
return value; \
} \
static inline void out##bwl##_local_p(unsigned type value, int port) { \
out##bwl##_local(value, port); \
slow_down_io(); \
} \
static inline unsigned type in##bwl##_local_p(int port) { \
unsigned type value = in##bwl##_local(port); \
slow_down_io(); \
return value; \
} \
__BUILDIO(bwl,bw,type) \
static inline void out##bwl##_p(unsigned type value, int port) { \
out##bwl(value, port); \
slow_down_io(); \
} \
static inline unsigned type in##bwl##_p(int port) { \
unsigned type value = in##bwl(port); \
slow_down_io(); \
return value; \
} \
static inline void outs##bwl(int port, const void *addr, unsigned long count) { \
__asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \
} \
static inline void ins##bwl(int port, void *addr, unsigned long count) { \
__asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \
}
BUILDIO(b,b,char)
BUILDIO(w,w,short)
BUILDIO(l,,int)
#endif
@@ -0,0 +1,82 @@
/* defines for inline arch setup functions */
#include <asm/apic.h>
/**
* do_timer_interrupt_hook - hook into timer tick
* @regs: standard registers from interrupt
*
* Description:
* This hook is called immediately after the timer interrupt is ack'd.
* It's primary purpose is to allow architectures that don't possess
* individual per CPU clocks (like the CPU APICs supply) to broadcast the
* timer interrupt as a means of triggering reschedules etc.
**/
static inline void do_timer_interrupt_hook(struct pt_regs *regs)
{
do_timer(regs);
/*
* In the SMP case we use the local APIC timer interrupt to do the
* profiling, except when we simulate SMP mode on a uniprocessor
* system, in that case we have to call the local interrupt handler.
*/
#ifndef CONFIG_X86_LOCAL_APIC
x86_do_profile(regs);
#else
if (!using_apic_timer)
smp_local_timer_interrupt(regs);
#endif
}
/* you can safely undefine this if you don't have the Neptune chipset */
#define BUGGY_NEPTUN_TIMER
/**
* do_timer_overflow - process a detected timer overflow condition
* @count: hardware timer interrupt count on overflow
*
* Description:
* This call is invoked when the jiffies count has not incremented but
* the hardware timer interrupt has. It means that a timer tick interrupt
* came along while the previous one was pending, thus a tick was missed
**/
static inline int do_timer_overflow(int count)
{
int i;
spin_lock(&i8259A_lock);
/*
* This is tricky when I/O APICs are used;
* see do_timer_interrupt().
*/
i = inb(0x20);
spin_unlock(&i8259A_lock);
/* assumption about timer being IRQ0 */
if (i & 0x01) {
/*
* We cannot detect lost timer interrupts ...
* well, that's why we call them lost, don't we? :)
* [hmm, on the Pentium and Alpha we can ... sort of]
*/
count -= LATCH;
} else {
#ifdef BUGGY_NEPTUN_TIMER
/*
* for the Neptun bug we know that the 'latch'
* command doesn't latch the high and low value
* of the counter atomically. Thus we have to
* substract 256 from the counter
* ... funny, isnt it? :)
*/
count -= 256;
#else
printk("do_slow_gettimeoffset(): hardware timer problem?\n");
#endif
}
return count;
}
@@ -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,145 @@
/*
* 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.
*/
/*
* 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
/*
* 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
/* #define TIMER_IRQ _EVENT_TIMER */
/*
* 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)
*/
#if 0
/*
* 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
#ifdef CONFIG_PCI_USE_VECTOR
#define NR_IRQS FIRST_SYSTEM_VECTOR
#define NR_IRQ_VECTORS NR_IRQS
#else
#ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
# define NR_IRQ_VECTORS NR_IRQS
# else
# define NR_IRQ_VECTORS (32 * NR_CPUS)
# endif
#else
#define NR_IRQS 16
#define NR_IRQ_VECTORS NR_IRQS
#endif
#endif
#endif
#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 128
#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
#define NR_DYNIRQS 128
#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_evtchn_to_irq(int evtchn);
extern void unbind_evtchn_from_irq(int evtchn);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_IRQ_VECTORS_H */
@@ -0,0 +1,13 @@
#ifndef __ASM_MACH_MPSPEC_H
#define __ASM_MACH_MPSPEC_H
/*
* a maximum of 16 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 16
#define MAX_IRQ_SOURCES 256
#define MAX_MP_BUSSES 32
#endif /* __ASM_MACH_MPSPEC_H */
@@ -0,0 +1,30 @@
/*
* arch/i386/mach-generic/mach_reboot.h
*
* Machine specific reboot functions for generic.
* Split out from reboot.c by Osamu Tomita <tomita@cinet.co.jp>
*/
#ifndef _MACH_REBOOT_H
#define _MACH_REBOOT_H
static inline void kb_wait(void)
{
int i;
for (i = 0; i < 0x10000; i++)
if ((inb_p(0x64) & 0x02) == 0)
break;
}
static inline void mach_reboot(void)
{
int i;
for (i = 0; i < 100; i++) {
kb_wait();
udelay(50);
outb(0xfe, 0x64); /* pulse reset low */
udelay(50);
}
}
#endif /* !_MACH_REBOOT_H */
@@ -0,0 +1,106 @@
/*
* include/asm-i386/mach-default/mach_resources.h
*
* Machine specific resource allocation for generic.
* Split out from setup.c by Osamu Tomita <tomita@cinet.co.jp>
*/
#ifndef _MACH_RESOURCES_H
#define _MACH_RESOURCES_H
struct resource standard_io_resources[] = {
{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
{ "pic1", 0x20, 0x21, IORESOURCE_BUSY },
{ "timer", 0x40, 0x5f, IORESOURCE_BUSY },
{ "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
{ "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
{ "pic2", 0xa0, 0xa1, IORESOURCE_BUSY },
{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
};
#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
/* System ROM resources */
#define MAXROMS 6
static struct resource rom_resources[MAXROMS] = {
{ "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
{ "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
};
#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
static inline void probe_video_rom(int roms)
{
unsigned long base;
unsigned char *romstart;
/* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
for (base = 0xC0000; base < 0xE0000; base += 2048) {
romstart = isa_bus_to_virt(base);
if (!romsignature(romstart))
continue;
request_resource(&iomem_resource, rom_resources + roms);
roms++;
break;
}
}
static inline void probe_extension_roms(int roms)
{
unsigned long base;
unsigned char *romstart;
/* Extension roms at C800:0000 - DFFF:0000 */
for (base = 0xC8000; base < 0xE0000; base += 2048) {
unsigned long length;
romstart = isa_bus_to_virt(base);
if (!romsignature(romstart))
continue;
length = romstart[2] * 512;
if (length) {
unsigned int i;
unsigned char chksum;
chksum = 0;
for (i = 0; i < length; i++)
chksum += romstart[i];
/* Good checksum? */
if (!chksum) {
rom_resources[roms].start = base;
rom_resources[roms].end = base + length - 1;
rom_resources[roms].name = "Extension ROM";
rom_resources[roms].flags = IORESOURCE_BUSY;
request_resource(&iomem_resource, rom_resources + roms);
roms++;
if (roms >= MAXROMS)
return;
}
}
}
/* Final check for motherboard extension rom at E000:0000 */
base = 0xE0000;
romstart = isa_bus_to_virt(base);
if (romsignature(romstart)) {
rom_resources[roms].start = base;
rom_resources[roms].end = base + 65535;
rom_resources[roms].name = "Extension ROM";
rom_resources[roms].flags = IORESOURCE_BUSY;
request_resource(&iomem_resource, rom_resources + roms);
}
}
static inline void request_graphics_resource(void)
{
request_resource(&iomem_resource, &vram_resource);
}
#endif /* !_MACH_RESOURCES_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,29 @@
/*
* include/asm-i386/mach-default/mach_traps.h
*
* Machine specific NMI handling for generic.
* Split out from traps.c by Osamu Tomita <tomita@cinet.co.jp>
*/
#ifndef _MACH_TRAPS_H
#define _MACH_TRAPS_H
static inline void clear_mem_error(unsigned char reason)
{
reason = (reason & 0xf) | 4;
outb(reason, 0x61);
}
static inline unsigned char get_nmi_reason(void)
{
return inb(0x61);
}
static inline void reassert_nmi(void)
{
outb(0x8f, 0x70);
inb(0x71); /* dummy */
outb(0x0f, 0x70);
inb(0x71); /* dummy */
}
#endif /* !_MACH_TRAPS_H */
@@ -0,0 +1,41 @@
/**
* 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 inline char * __init machine_specific_memory_setup(void)
{
char *who;
unsigned long start_pfn, max_pfn;
who = "Xen";
start_pfn = 0;
max_pfn = 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;
}
extern void hypervisor_callback(void);
extern void failsafe_callback(void);
static inline void __init machine_specific_arch_setup(void)
{
HYPERVISOR_set_callbacks(
__KERNEL_CS, (unsigned long)hypervisor_callback,
__KERNEL_CS, (unsigned long)failsafe_callback);
clear_bit(X86_FEATURE_VME, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_DE, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability);
}
@@ -0,0 +1,5 @@
/* Hook to call BIOS initialisation function */
#define ARCH_SETUP machine_specific_arch_setup();
static inline void __init machine_specific_arch_setup(void);
@@ -0,0 +1,263 @@
#ifndef __ASM_MSR_H
#define __ASM_MSR_H
#include <linux/smp.h>
#include <asm/hypervisor.h>
/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
* pointer indirection), this allows gcc to optimize better
*/
#define rdmsr(_msr,_val1,_val2) do { \
dom0_op_t op; \
op.cmd = DOM0_MSR; \
op.u.msr.write = 0; \
op.u.msr.msr = (_msr); \
op.u.msr.cpu_mask = (1 << smp_processor_id()); \
HYPERVISOR_dom0_op(&op); \
(_val1) = op.u.msr.out1; \
(_val2) = op.u.msr.out2; \
} while(0)
#define wrmsr(_msr,_val1,_val2) do { \
dom0_op_t op; \
op.cmd = DOM0_MSR; \
op.u.msr.write = 1; \
op.u.msr.cpu_mask = (1 << smp_processor_id()); \
op.u.msr.msr = (_msr); \
op.u.msr.in1 = (_val1); \
op.u.msr.in2 = (_val2); \
HYPERVISOR_dom0_op(&op); \
} while(0)
#define rdmsrl(msr,val) do { \
unsigned long l__,h__; \
rdmsr (msr, l__, h__); \
val = l__; \
val |= ((u64)h__<<32); \
} while(0)
static inline void wrmsrl (unsigned long msr, unsigned long long val)
{
unsigned long lo, hi;
lo = (unsigned long) val;
hi = val >> 32;
wrmsr (msr, lo, hi);
}
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define rdtscl(low) \
__asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
#define rdtscll(val) \
__asm__ __volatile__("rdtsc" : "=A" (val))
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
#define rdpmc(counter,low,high) \
__asm__ __volatile__("rdpmc" \
: "=a" (low), "=d" (high) \
: "c" (counter))
/* symbolic names for some interesting MSRs */
/* Intel defined MSRs. */
#define MSR_IA32_P5_MC_ADDR 0
#define MSR_IA32_P5_MC_TYPE 1
#define MSR_IA32_PLATFORM_ID 0x17
#define MSR_IA32_EBL_CR_POWERON 0x2a
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
#define MSR_IA32_UCODE_WRITE 0x79
#define MSR_IA32_UCODE_REV 0x8b
#define MSR_P6_PERFCTR0 0xc1
#define MSR_P6_PERFCTR1 0xc2
#define MSR_IA32_BBL_CR_CTL 0x119
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define MSR_IA32_MCG_CAP 0x179
#define MSR_IA32_MCG_STATUS 0x17a
#define MSR_IA32_MCG_CTL 0x17b
/* P4/Xeon+ specific */
#define MSR_IA32_MCG_EAX 0x180
#define MSR_IA32_MCG_EBX 0x181
#define MSR_IA32_MCG_ECX 0x182
#define MSR_IA32_MCG_EDX 0x183
#define MSR_IA32_MCG_ESI 0x184
#define MSR_IA32_MCG_EDI 0x185
#define MSR_IA32_MCG_EBP 0x186
#define MSR_IA32_MCG_ESP 0x187
#define MSR_IA32_MCG_EFLAGS 0x188
#define MSR_IA32_MCG_EIP 0x189
#define MSR_IA32_MCG_RESERVED 0x18A
#define MSR_P6_EVNTSEL0 0x186
#define MSR_P6_EVNTSEL1 0x187
#define MSR_IA32_PERF_STATUS 0x198
#define MSR_IA32_PERF_CTL 0x199
#define MSR_IA32_THERM_CONTROL 0x19a
#define MSR_IA32_THERM_INTERRUPT 0x19b
#define MSR_IA32_THERM_STATUS 0x19c
#define MSR_IA32_MISC_ENABLE 0x1a0
#define MSR_IA32_DEBUGCTLMSR 0x1d9
#define MSR_IA32_LASTBRANCHFROMIP 0x1db
#define MSR_IA32_LASTBRANCHTOIP 0x1dc
#define MSR_IA32_LASTINTFROMIP 0x1dd
#define MSR_IA32_LASTINTTOIP 0x1de
#define MSR_IA32_MC0_CTL 0x400
#define MSR_IA32_MC0_STATUS 0x401
#define MSR_IA32_MC0_ADDR 0x402
#define MSR_IA32_MC0_MISC 0x403
/* Pentium IV performance counter MSRs */
#define MSR_P4_BPU_PERFCTR0 0x300
#define MSR_P4_BPU_PERFCTR1 0x301
#define MSR_P4_BPU_PERFCTR2 0x302
#define MSR_P4_BPU_PERFCTR3 0x303
#define MSR_P4_MS_PERFCTR0 0x304
#define MSR_P4_MS_PERFCTR1 0x305
#define MSR_P4_MS_PERFCTR2 0x306
#define MSR_P4_MS_PERFCTR3 0x307
#define MSR_P4_FLAME_PERFCTR0 0x308
#define MSR_P4_FLAME_PERFCTR1 0x309
#define MSR_P4_FLAME_PERFCTR2 0x30a
#define MSR_P4_FLAME_PERFCTR3 0x30b
#define MSR_P4_IQ_PERFCTR0 0x30c
#define MSR_P4_IQ_PERFCTR1 0x30d
#define MSR_P4_IQ_PERFCTR2 0x30e
#define MSR_P4_IQ_PERFCTR3 0x30f
#define MSR_P4_IQ_PERFCTR4 0x310
#define MSR_P4_IQ_PERFCTR5 0x311
#define MSR_P4_BPU_CCCR0 0x360
#define MSR_P4_BPU_CCCR1 0x361
#define MSR_P4_BPU_CCCR2 0x362
#define MSR_P4_BPU_CCCR3 0x363
#define MSR_P4_MS_CCCR0 0x364
#define MSR_P4_MS_CCCR1 0x365
#define MSR_P4_MS_CCCR2 0x366
#define MSR_P4_MS_CCCR3 0x367
#define MSR_P4_FLAME_CCCR0 0x368
#define MSR_P4_FLAME_CCCR1 0x369
#define MSR_P4_FLAME_CCCR2 0x36a
#define MSR_P4_FLAME_CCCR3 0x36b
#define MSR_P4_IQ_CCCR0 0x36c
#define MSR_P4_IQ_CCCR1 0x36d
#define MSR_P4_IQ_CCCR2 0x36e
#define MSR_P4_IQ_CCCR3 0x36f
#define MSR_P4_IQ_CCCR4 0x370
#define MSR_P4_IQ_CCCR5 0x371
#define MSR_P4_ALF_ESCR0 0x3ca
#define MSR_P4_ALF_ESCR1 0x3cb
#define MSR_P4_BPU_ESCR0 0x3b2
#define MSR_P4_BPU_ESCR1 0x3b3
#define MSR_P4_BSU_ESCR0 0x3a0
#define MSR_P4_BSU_ESCR1 0x3a1
#define MSR_P4_CRU_ESCR0 0x3b8
#define MSR_P4_CRU_ESCR1 0x3b9
#define MSR_P4_CRU_ESCR2 0x3cc
#define MSR_P4_CRU_ESCR3 0x3cd
#define MSR_P4_CRU_ESCR4 0x3e0
#define MSR_P4_CRU_ESCR5 0x3e1
#define MSR_P4_DAC_ESCR0 0x3a8
#define MSR_P4_DAC_ESCR1 0x3a9
#define MSR_P4_FIRM_ESCR0 0x3a4
#define MSR_P4_FIRM_ESCR1 0x3a5
#define MSR_P4_FLAME_ESCR0 0x3a6
#define MSR_P4_FLAME_ESCR1 0x3a7
#define MSR_P4_FSB_ESCR0 0x3a2
#define MSR_P4_FSB_ESCR1 0x3a3
#define MSR_P4_IQ_ESCR0 0x3ba
#define MSR_P4_IQ_ESCR1 0x3bb
#define MSR_P4_IS_ESCR0 0x3b4
#define MSR_P4_IS_ESCR1 0x3b5
#define MSR_P4_ITLB_ESCR0 0x3b6
#define MSR_P4_ITLB_ESCR1 0x3b7
#define MSR_P4_IX_ESCR0 0x3c8
#define MSR_P4_IX_ESCR1 0x3c9
#define MSR_P4_MOB_ESCR0 0x3aa
#define MSR_P4_MOB_ESCR1 0x3ab
#define MSR_P4_MS_ESCR0 0x3c0
#define MSR_P4_MS_ESCR1 0x3c1
#define MSR_P4_PMH_ESCR0 0x3ac
#define MSR_P4_PMH_ESCR1 0x3ad
#define MSR_P4_RAT_ESCR0 0x3bc
#define MSR_P4_RAT_ESCR1 0x3bd
#define MSR_P4_SAAT_ESCR0 0x3ae
#define MSR_P4_SAAT_ESCR1 0x3af
#define MSR_P4_SSU_ESCR0 0x3be
#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
#define MSR_P4_TBPU_ESCR0 0x3c2
#define MSR_P4_TBPU_ESCR1 0x3c3
#define MSR_P4_TC_ESCR0 0x3c4
#define MSR_P4_TC_ESCR1 0x3c5
#define MSR_P4_U2L_ESCR0 0x3b0
#define MSR_P4_U2L_ESCR1 0x3b1
/* AMD Defined MSRs */
#define MSR_K6_EFER 0xC0000080
#define MSR_K6_STAR 0xC0000081
#define MSR_K6_WHCR 0xC0000082
#define MSR_K6_UWCCR 0xC0000085
#define MSR_K6_EPMR 0xC0000086
#define MSR_K6_PSOR 0xC0000087
#define MSR_K6_PFIR 0xC0000088
#define MSR_K7_EVNTSEL0 0xC0010000
#define MSR_K7_EVNTSEL1 0xC0010001
#define MSR_K7_EVNTSEL2 0xC0010002
#define MSR_K7_EVNTSEL3 0xC0010003
#define MSR_K7_PERFCTR0 0xC0010004
#define MSR_K7_PERFCTR1 0xC0010005
#define MSR_K7_PERFCTR2 0xC0010006
#define MSR_K7_PERFCTR3 0xC0010007
#define MSR_K7_HWCR 0xC0010015
#define MSR_K7_CLK_CTL 0xC001001b
#define MSR_K7_FID_VID_CTL 0xC0010041
#define MSR_K7_FID_VID_STATUS 0xC0010042
/* Centaur-Hauls/IDT defined MSRs. */
#define MSR_IDT_FCR1 0x107
#define MSR_IDT_FCR2 0x108
#define MSR_IDT_FCR3 0x109
#define MSR_IDT_FCR4 0x10a
#define MSR_IDT_MCR0 0x110
#define MSR_IDT_MCR1 0x111
#define MSR_IDT_MCR2 0x112
#define MSR_IDT_MCR3 0x113
#define MSR_IDT_MCR4 0x114
#define MSR_IDT_MCR5 0x115
#define MSR_IDT_MCR6 0x116
#define MSR_IDT_MCR7 0x117
#define MSR_IDT_MCR_CTRL 0x120
/* VIA Cyrix defined MSRs*/
#define MSR_VIA_FCR 0x1107
#define MSR_VIA_LONGHAUL 0x110a
#define MSR_VIA_RNG 0x110b
#define MSR_VIA_BCR2 0x1147
/* Transmeta defined MSRs */
#define MSR_TMTA_LONGRUN_CTRL 0x80868010
#define MSR_TMTA_LONGRUN_FLAGS 0x80868011
#define MSR_TMTA_LRTI_READOUT 0x80868018
#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
#endif /* __ASM_MSR_H */
@@ -0,0 +1,199 @@
#ifndef _I386_PAGE_H
#define _I386_PAGE_H
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/config.h>
#include <linux/types.h>
#include <asm/hypervisor-ifs/hypervisor-if.h>
#ifdef CONFIG_X86_USE_3DNOW
#include <asm/mmx.h>
#define clear_page(page) mmx_clear_page((void *)(page))
#define copy_page(to,from) mmx_copy_page(to,from)
#else
/*
* On older X86 processors it's not a win to use MMX here it seems.
* Maybe the K6-III ?
*/
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
#endif
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
extern unsigned long *phys_to_machine_mapping;
#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_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..
*/
#ifdef CONFIG_X86_PAE
typedef struct { unsigned long pte_low, pte_high; } pte_t;
typedef struct { unsigned long long pmd; } pmd_t;
typedef struct { unsigned long long pgd; } pgd_t;
#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
#define HPAGE_SHIFT 21
#else
typedef struct { unsigned long pte_low; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
#define boot_pte_t pte_t /* or would you rather have a typedef */
#if 0 /* XXXcl for MMU_UPDATE_DEBUG */
static inline unsigned long pte_val(pte_t x)
{
unsigned long ret = x.pte_low;
if ( (ret & 1) ) ret = machine_to_phys(ret);
return ret;
}
#else
#define pte_val(x) (((x).pte_low & 1) ? machine_to_phys((x).pte_low) : (x).pte_low)
#endif
#define pte_val_ma(x) ((x).pte_low)
#define HPAGE_SHIFT 22
#endif
#define PTE_MASK PAGE_MASK
#ifdef CONFIG_HUGETLB_PAGE
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#endif
typedef struct { unsigned long pgprot; } pgprot_t;
static inline unsigned long pmd_val(pmd_t x)
{
unsigned long ret = x.pmd;
if ( (ret & 1) ) ret = machine_to_phys(ret);
return ret;
}
#define pgd_val(x) ({ BUG(); (unsigned long)0; })
#define pgprot_val(x) ((x).pgprot)
static inline pte_t __pte(unsigned long x)
{
if ( (x & 1) ) x = phys_to_machine(x);
return ((pte_t) { (x) });
}
#define __pte_ma(x) ((pte_t) { (x) } )
static inline pmd_t __pmd(unsigned long x)
{
if ( (x & 1) ) x = phys_to_machine(x);
return ((pmd_t) { (x) });
}
#define __pgd(x) ({ BUG(); (pgprot_t) { 0 }; })
#define __pgprot(x) ((pgprot_t) { (x) } )
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/*
* This handles the memory map.. We could make this a config
* option, but too many people screw it up, and too few need
* it.
*
* A __PAGE_OFFSET of 0xC0000000 means that the kernel has
* a virtual address space of one gigabyte, which limits the
* amount of physical memory you can use to about 950MB.
*
* If you want more physical memory than this then see the CONFIG_HIGHMEM4G
* and CONFIG_HIGHMEM64G options in the kernel configuration.
*/
/*
* This much address space is reserved for vmalloc() and iomap()
* as well as fixmap mappings.
*/
#define __VMALLOC_RESERVE (128 << 20)
#ifndef __ASSEMBLY__
/* Pure 2^n version of get_order */
static __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__ */
/*
* XXXcl two options for PAGE_OFFSET
* - 0xC0000000:
* change text offset in arch/xen/i386/kernel/vmlinux.lds.S
* change __pa/__va macros
* - 0xC0100000:
* change TASK_SIZE
*/
#ifdef __ASSEMBLY__
#define __PAGE_OFFSET (0xC0100000)
#else
#define __PAGE_OFFSET (0xC0100000UL)
#endif
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)
#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#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 /* !CONFIG_DISCONTIGMEM */
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
#endif /* __KERNEL__ */
#endif /* _I386_PAGE_H */
@@ -0,0 +1,22 @@
#ifndef _ASMi386_PARAM_H
#define _ASMi386_PARAM_H
#ifdef __KERNEL__
# define HZ 100/* 0 */ /* 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,59 @@
#ifndef _I386_PGALLOC_H
#define _I386_PGALLOC_H
#include <linux/config.h>
#include <asm/processor.h>
#include <asm/fixmap.h>
#include <linux/threads.h>
#include <linux/mm.h> /* for struct page */
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
{
set_pmd(pmd, __pmd(_PAGE_TABLE +
((unsigned long long)page_to_pfn(pte) <<
(unsigned long long) PAGE_SHIFT)));
flush_page_update_queue(); /* XXXcl flush */
}
/*
* Allocate and free page tables.
*/
extern pgd_t *pgd_alloc(struct mm_struct *);
extern void pgd_free(pgd_t *pgd);
extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
static inline void pte_free_kernel(pte_t *pte)
{
free_page((unsigned long)pte);
}
static inline void pte_free(struct page *pte)
{
__free_page(pte);
}
#define __pte_free_tlb(tlb,pte) do { \
tlb_remove_page((tlb),(pte)); \
flush_page_update_queue(); /* XXXcl flush */ \
} while (0)
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
* (In the PAE case we free the pmds as part of the pgd.)
*/
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
#define pmd_free(x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
#define check_pgt_cache() do { } while (0)
#endif /* _I386_PGALLOC_H */
@@ -0,0 +1,98 @@
#ifndef _I386_PGTABLE_2LEVEL_H
#define _I386_PGTABLE_2LEVEL_H
/*
* traditional i386 two-level paging structure:
*/
#define PGDIR_SHIFT 22
#define PTRS_PER_PGD 1024
#define PTRS_PER_PGD_NO_HV (HYPERVISOR_VIRT_START >> PGDIR_SHIFT)
/*
* the i386 is two-level, so we don't really have any
* PMD directory physically.
*/
#define PMD_SHIFT 22
#define PTRS_PER_PMD 1
#define PTRS_PER_PTE 1024
#define pte_ERROR(e) \
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
#define pmd_ERROR(e) \
printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded
* into the pgd entry)
*/
static inline int pgd_none(pgd_t pgd) { return 0; }
static inline int pgd_bad(pgd_t pgd) { return 0; }
static inline int pgd_present(pgd_t pgd) { return 1; }
#define pgd_clear(xp) do { } while (0)
/*
* Certain architectures need to do special things when PTEs
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
#define set_pte(pteptr, pteval) queue_l1_entry_update(pteptr, (pteval).pte_low)
#define set_pte_atomic(pteptr, pteval) queue_l1_entry_update(pteptr, (pteval).pte_low)
/*
* (pmds are folded into pgds so this doesn't get actually called,
* but the define is needed for a generic inline function.)
*/
#define set_pmd(pmdptr, pmdval) queue_l2_entry_update((pmdptr), (pmdval).pmd)
#define set_pgd(pgdptr, pgdval) ((void)0)
#define pgd_page(pgd) \
((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
{
return (pmd_t *) dir;
}
/*
* 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_low)
queue_l1_entry_update(xp, 0);
return pte;
}
#define pte_same(a, b) ((a).pte_low == (b).pte_low)
#define pte_page(x) pfn_to_page(pte_pfn(x))
#define pte_none(x) (!(x).pte_low)
/* XXXcl check valid because msync.c:filemap_sync_pte calls without pte_present check */
#define pte_pfn(x) ((unsigned long)((((x).pte_low & 1 ? machine_to_phys((x).pte_low) : (x).pte_low) >> PAGE_SHIFT)))
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define pfn_pte_ma(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
/*
* Bits 0, 6 and 7 are taken, split up the 29 bits of offset
* into this range:
*/
#define PTE_FILE_MAX_BITS 29
#define pte_to_pgoff(pte) \
((((pte).pte_low >> 1) & 0x1f ) + (((pte).pte_low >> 8) << 5 ))
#define pgoff_to_pte(off) \
((pte_t) { (((off) & 0x1f) << 1) + (((off) >> 5) << 8) + _PAGE_FILE })
#endif /* _I386_PGTABLE_2LEVEL_H */
@@ -0,0 +1,457 @@
#ifndef _I386_PGTABLE_H
#define _I386_PGTABLE_H
#include <linux/config.h>
#include <asm/hypervisor.h>
/*
* The Linux memory management assumes a three-level page table setup. On
* the i386, we use that, but "fold" the mid level into the top-level page
* table, so that we physically have the same two-level page table as the
* i386 mmu expects.
*
* This file contains the functions and defines necessary to modify and use
* the i386 page table tree.
*/
#ifndef __ASSEMBLY__
#include <asm/processor.h>
#include <asm/fixmap.h>
#include <linux/threads.h>
#ifndef _I386_BITOPS_H
#include <asm/bitops.h>
#endif
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/spinlock.h>
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
extern unsigned long empty_zero_page[1024];
extern pgd_t swapper_pg_dir[1024];
extern kmem_cache_t *pgd_cache;
extern kmem_cache_t *pmd_cache;
extern spinlock_t pgd_lock;
extern struct page *pgd_list;
void pmd_ctor(void *, kmem_cache_t *, unsigned long);
void pgd_ctor(void *, kmem_cache_t *, unsigned long);
void pgd_dtor(void *, kmem_cache_t *, unsigned long);
void pgtable_cache_init(void);
void paging_init(void);
#endif /* !__ASSEMBLY__ */
/*
* The Linux x86 paging architecture is 'compile-time dual-mode', it
* implements both the traditional 2-level x86 page tables and the
* newer 3-level PAE-mode page tables.
*/
#ifndef __ASSEMBLY__
#ifdef CONFIG_X86_PAE
# include <asm/pgtable-3level.h>
#else
# include <asm/pgtable-2level.h>
#endif
#endif
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_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
#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
#define TWOLEVEL_PGDIR_SHIFT 22
#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
#ifndef __ASSEMBLY__
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
* any out-of-bounds memory accesses will hopefully be caught.
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
#define VMALLOC_OFFSET (8*1024*1024)
extern void * high_memory;
#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
~(VMALLOC_OFFSET-1))
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
#else
# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
#endif
/*
* The 4MB page is guessing.. Detailed in the infamous "Chapter H"
* of the Pentium details, but assuming intel did the straightforward
* thing, this bit set in the page directory entry just means that
* the page directory entry points directly to a 4MB-aligned block of
* memory.
*/
#define _PAGE_BIT_PRESENT 0
#define _PAGE_BIT_RW 1
#define _PAGE_BIT_USER 2
#define _PAGE_BIT_PWT 3
#define _PAGE_BIT_PCD 4
#define _PAGE_BIT_ACCESSED 5
#define _PAGE_BIT_DIRTY 6
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
#define _PAGE_BIT_UNUSED2 10
#define _PAGE_BIT_UNUSED3 11
#define _PAGE_PRESENT 0x001
#define _PAGE_RW 0x002
#define _PAGE_USER 0x004
#define _PAGE_PWT 0x008
#define _PAGE_PCD 0x010
#define _PAGE_ACCESSED 0x020
#define _PAGE_DIRTY 0x040
#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */
#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */
#define _PAGE_UNUSED1 0x200 /* available for programmer */
#define _PAGE_UNUSED2 0x400
#define _PAGE_UNUSED3 0x800
#define _PAGE_FILE 0x040 /* set:pagecache unset:swap */
#define _PAGE_PROTNONE 0x080 /* If not present */
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define _PAGE_KERNEL \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
extern unsigned long __PAGE_KERNEL;
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
/*
* The i386 can't do page protection for execute, and considers that
* the same are read. Also, write permissions imply read permissions.
* This is the closest we can get..
*/
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
#define __P010 PAGE_COPY
#define __P011 PAGE_COPY
#define __P100 PAGE_READONLY
#define __P101 PAGE_READONLY
#define __P110 PAGE_COPY
#define __P111 PAGE_COPY
#define __S000 PAGE_NONE
#define __S001 PAGE_READONLY
#define __S010 PAGE_SHARED
#define __S011 PAGE_SHARED
#define __S100 PAGE_READONLY
#define __S101 PAGE_READONLY
#define __S110 PAGE_SHARED
#define __S111 PAGE_SHARED
/*
* Define this if things work differently on an i386 and an i486:
* it will (on an i486) warn about kernel memory accesses that are
* done without a 'verify_area(VERIFY_WRITE,..)'
*/
#undef TEST_VERIFY_AREA
/* The boot page tables (all created as a single array) */
extern unsigned long pg0[];
#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
#define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0)
#define pmd_none(x) (!pmd_val(x))
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
/* pmd_clear below */
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_exec(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
/*
* The following only works if pte_present() is not true.
*/
static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; }
static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
static inline int ptep_test_and_clear_dirty(pte_t *ptep)
{
unsigned long pteval = *(unsigned long *)ptep;
int ret = pteval & _PAGE_DIRTY;
if (ret)
queue_l1_entry_update(ptep, pteval & ~_PAGE_DIRTY);
return ret;
}
static inline int ptep_test_and_clear_young(pte_t *ptep)
{
unsigned long pteval = *(unsigned long *)ptep;
int ret = pteval & _PAGE_ACCESSED;
if (ret)
queue_l1_entry_update(ptep, pteval & ~_PAGE_ACCESSED);
return ret;
}
static inline void ptep_set_wrprotect(pte_t *ptep)
{
unsigned long pteval = *(unsigned long *)ptep;
if ((pteval & _PAGE_RW))
queue_l1_entry_update(ptep, pteval & ~_PAGE_RW);
}
static inline void ptep_mkdirty(pte_t *ptep)
{
unsigned long pteval = *(unsigned long *)ptep;
if (!(pteval & _PAGE_DIRTY))
queue_l1_entry_update(ptep, pteval | _PAGE_DIRTY);
}
/*
* Macro to mark a page protection value as "uncacheable". On processors which do not support
* it, this is a no-op.
*/
#define pgprot_noncached(prot) ((boot_cpu_data.x86 > 3) \
? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) : (prot))
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
#define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
pte.pte_low &= _PAGE_CHG_MASK;
pte.pte_low |= pgprot_val(newprot);
return pte;
}
#define page_pte(page) page_pte_prot(page, __pgprot(0))
#define pmd_page_kernel(pmd) \
((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
#define pmd_clear(xp) do { \
pmd_t p = *(xp); \
set_pmd(xp, __pmd(0)); \
__make_page_writeable((void *)pmd_page_kernel(p)); \
} while (0)
#ifndef CONFIG_DISCONTIGMEM
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
#endif /* !CONFIG_DISCONTIGMEM */
#define pmd_large(pmd) \
((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT))
/*
* the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
*
* this macro returns the index of the entry in the pgd page which would
* control the given virtual address
*/
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
/*
* pgd_offset() returns a (pgd_t *)
* pgd_index() is used get the offset into the pgd page's array of pgd_t's;
*/
#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/*
* a shortcut which implies the use of the kernel's pgd, instead
* of a process's
*/
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/*
* the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
*
* this macro returns the index of the entry in the pmd page which would
* control the given virtual address
*/
#define pmd_index(address) \
(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
/*
* the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
*
* this macro returns the index of the entry in the pte page which would
* control the given virtual address
*/
#define pte_index(address) \
(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
#if defined(CONFIG_HIGHPTE)
#define pte_offset_map(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
#define pte_offset_map_nested(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
#else
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
#endif
/*
* The i386 doesn't have any external MMU info: the kernel page
* tables contain all the necessary information.
*
* Also, 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 update_mmu_cache(vma,address,pte) do { } while (0)
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
do { \
if (__dirty) { \
queue_l1_entry_update((__ptep), (__entry).pte_low); \
flush_tlb_page(__vma, __address); \
} \
} while (0)
/* Encode and de-code a swap entry */
#define __swp_type(x) (((x).val >> 1) & 0x1f)
#define __swp_offset(x) ((x).val >> 8)
#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
static inline void __make_page_readonly(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)&~_PAGE_RW);
}
static inline void __make_page_writeable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)|_PAGE_RW);
}
static inline void make_page_readonly(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)&~_PAGE_RW);
if ( (unsigned long)va >= VMALLOC_START )
__make_page_readonly(machine_to_virt(
*(unsigned long *)pte&PAGE_MASK));
}
static inline void make_page_writeable(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
queue_l1_entry_update(pte, (*(unsigned long *)pte)|_PAGE_RW);
if ( (unsigned long)va >= VMALLOC_START )
__make_page_writeable(machine_to_virt(
*(unsigned long *)pte&PAGE_MASK));
}
static inline void make_pages_readonly(void *va, unsigned int nr)
{
while ( nr-- != 0 )
{
make_page_readonly(va);
va = (void *)((unsigned long)va + PAGE_SIZE);
}
}
static inline void make_pages_writeable(void *va, unsigned int nr)
{
while ( nr-- != 0 )
{
make_page_writeable(va);
va = (void *)((unsigned long)va + PAGE_SIZE);
}
}
static inline unsigned long arbitrary_virt_to_phys(void *va)
{
pgd_t *pgd = pgd_offset_k((unsigned long)va);
pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
pte_t *pte = pte_offset_kernel(pmd, (unsigned long)va);
unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
return pa | ((unsigned long)va & (PAGE_SIZE-1));
}
#endif /* !__ASSEMBLY__ */
#ifndef CONFIG_DISCONTIGMEM
#define kern_addr_valid(addr) (1)
#endif /* !CONFIG_DISCONTIGMEM */
#define io_remap_page_range remap_page_range
#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 /* _I386_PGTABLE_H */
@@ -0,0 +1,667 @@
/*
* include/asm-i386/processor.h
*
* Copyright (C) 1994 Linus Torvalds
*/
#ifndef __ASM_I386_PROCESSOR_H
#define __ASM_I386_PROCESSOR_H
#include <asm/vm86.h>
#include <asm/math_emu.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/types.h>
#include <asm/sigcontext.h>
#include <asm/cpufeature.h>
#include <asm/msr.h>
#include <asm/system.h>
#include <linux/cache.h>
#include <linux/config.h>
#include <linux/threads.h>
/* flag for disabling the tsc */
extern int tsc_disable;
struct desc_struct {
unsigned long a,b;
};
#define desc_empty(desc) \
(!((desc)->a + (desc)->b))
#define desc_equal(desc1, desc2) \
(((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
* Members of this structure are referenced in head.S, so think twice
* before touching them. [mj]
*/
struct cpuinfo_x86 {
__u8 x86; /* CPU family */
__u8 x86_vendor; /* CPU vendor */
__u8 x86_model;
__u8 x86_mask;
char wp_works_ok; /* It doesn't on 386's */
char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
char hard_math;
char rfu;
int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
unsigned long x86_capability[NCAPINTS];
char x86_vendor_id[16];
char x86_model_id[64];
int x86_cache_size; /* in KB - valid for CPUS which support this
call */
int x86_cache_alignment; /* In bytes */
int fdiv_bug;
int f00f_bug;
int coma_bug;
unsigned long loops_per_jiffy;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
#define X86_VENDOR_AMD 2
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
#define X86_VENDOR_NUM 9
#define X86_VENDOR_UNKNOWN 0xff
/*
* capabilities of CPUs
*/
extern struct cpuinfo_x86 boot_cpu_data;
extern struct cpuinfo_x86 new_cpu_data;
extern struct tss_struct init_tss[NR_CPUS];
extern struct tss_struct doublefault_tss;
extern pgd_t *cur_pgd; /* XXXsmp */
#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_fpu_irq;
extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
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 */
/*
* Generic CPUID function
*/
static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
{
__asm__("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (op));
}
/*
* CPUID functions returning a single datum
*/
static inline unsigned int cpuid_eax(unsigned int op)
{
unsigned int eax;
__asm__("cpuid"
: "=a" (eax)
: "0" (op)
: "bx", "cx", "dx");
return eax;
}
static inline unsigned int cpuid_ebx(unsigned int op)
{
unsigned int eax, ebx;
__asm__("cpuid"
: "=a" (eax), "=b" (ebx)
: "0" (op)
: "cx", "dx" );
return ebx;
}
static inline unsigned int cpuid_ecx(unsigned int op)
{
unsigned int eax, ecx;
__asm__("cpuid"
: "=a" (eax), "=c" (ecx)
: "0" (op)
: "bx", "dx" );
return ecx;
}
static inline unsigned int cpuid_edx(unsigned int op)
{
unsigned int eax, edx;
__asm__("cpuid"
: "=a" (eax), "=d" (edx)
: "0" (op)
: "bx", "cx");
return edx;
}
#define load_cr3(pgdir) do { \
queue_pt_switch(__pa(pgdir)); \
flush_page_update_queue(); \
cur_pgd = pgdir; /* XXXsmp */ \
} while (/* CONSTCOND */0)
/*
* 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:
printk("Xen unsupported cr4 update\n");
BUG();
}
}
static inline void clear_in_cr4 (unsigned long mask)
{
mmu_cr4_features &= ~mask;
__asm__("movl %%cr4,%%eax\n\t"
"andl %0,%%eax\n\t"
"movl %%eax,%%cr4\n"
: : "irg" (~mask)
:"ax");
}
/*
* NSC/Cyrix CPU configuration register indexes
*/
#define CX86_PCR0 0x20
#define CX86_GCR 0xb8
#define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1
#define CX86_CCR2 0xc2
#define CX86_CCR3 0xc3
#define CX86_CCR4 0xe8
#define CX86_CCR5 0xe9
#define CX86_CCR6 0xea
#define CX86_CCR7 0xeb
#define CX86_PCR1 0xf0
#define CX86_DIR0 0xfe
#define CX86_DIR1 0xff
#define CX86_ARR_BASE 0xc4
#define CX86_RCR_BASE 0xdc
/*
* NSC/Cyrix CPU indexed register access macros
*/
#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
#define setCx86(reg, data) do { \
outb((reg), 0x22); \
outb((data), 0x23); \
} while (0)
/*
* Bus types (default is ISA, but people can check others with these..)
* pc98 indicates PC98 systems (CBUS)
*/
extern int MCA_bus;
#ifdef CONFIG_X86_PC9800
#define pc98 1
#else
#define pc98 0
#endif
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));
}
/* from system description table in BIOS. Mostly for MCA use, but
others may find it useful. */
extern unsigned int machine_id;
extern unsigned int machine_submodel_id;
extern unsigned int BIOS_revision;
extern unsigned int mca_pentium_flag;
/*
* User space process size: 3GB (default).
*/
#define TASK_SIZE (PAGE_OFFSET & PGDIR_MASK)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
/*
* Size of io_bitmap, covering ports 0 to 0x3ff.
*/
#define IO_BITMAP_BITS 1024
#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_fsave_struct {
long cwd;
long swd;
long twd;
long fip;
long fcs;
long foo;
long fos;
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
long status; /* software status information */
};
struct i387_fxsave_struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd;
unsigned short fop;
long fip;
long fcs;
long foo;
long fos;
long mxcsr;
long mxcsr_mask;
long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
long padding[56];
} __attribute__ ((aligned (16)));
struct i387_soft_struct {
long cwd;
long swd;
long twd;
long fip;
long fcs;
long foo;
long fos;
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
unsigned char ftop, changed, lookahead, no_update, rm, alimit;
struct info *info;
unsigned long entry_eip;
};
union i387_union {
struct i387_fsave_struct fsave;
struct i387_fxsave_struct fxsave;
struct i387_soft_struct soft;
};
typedef struct {
unsigned long seg;
} mm_segment_t;
struct tss_struct {
unsigned short back_link,__blh;
unsigned long esp0;
unsigned short ss0,__ss0h;
unsigned long esp1;
unsigned short ss1,__ss1h; /* ss1 is used to cache MSR_IA32_SYSENTER_CS */
unsigned long esp2;
unsigned short ss2,__ss2h;
unsigned long __cr3;
unsigned long eip;
unsigned long eflags;
unsigned long eax,ecx,edx,ebx;
unsigned long esp;
unsigned long ebp;
unsigned long esi;
unsigned long edi;
unsigned short es, __esh;
unsigned short cs, __csh;
unsigned short ss, __ssh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
unsigned short ldt, __ldth;
unsigned short trace, io_bitmap_base;
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
* bitmap. The extra byte must be all 1 bits, and must
* be within the limit.
*/
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
/*
* pads the TSS to be cacheline-aligned (size is 0x100)
*/
unsigned long __cacheline_filler[5];
/*
* .. and then another 0x100 bytes for emergency kernel stack
*/
unsigned long stack[64];
} __attribute__((packed));
#define ARCH_MIN_TASKALIGN 16
struct thread_struct {
/* cached TLS descriptors. */
struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
unsigned long esp0;
unsigned long sysenter_cs;
unsigned long eip;
unsigned long esp;
unsigned long fs;
unsigned long gs;
/* Hardware debugging registers */
unsigned long debugreg[8]; /* %%db0-7 debug registers */
/* fault info */
unsigned long cr2, trap_no, error_code;
/* floating point info */
union i387_union i387;
/* virtual 86 mode info */
struct vm86_struct __user * vm86_info;
unsigned long screen_bitmap;
unsigned long v86flags, v86mask, saved_esp0;
unsigned int saved_fs, saved_gs;
/* IO permissions */
unsigned long *io_bitmap_ptr;
};
#define INIT_THREAD { \
.vm86_info = NULL, \
.sysenter_cs = __KERNEL_CS, \
.io_bitmap_ptr = NULL, \
}
/*
* Note that the .io_bitmap member must be extra-big. This is because
* the CPU will access an additional byte beyond the end of the IO
* permission bitmap. The extra byte must be all 1 bits, and must
* be within the limit.
*/
#define INIT_TSS { \
.esp0 = sizeof(init_stack) + (long)&init_stack, \
.ss0 = __KERNEL_DS, \
.esp1 = sizeof(init_tss[0]) + (long)&init_tss[0], \
.ss1 = __KERNEL_CS, \
.ldt = GDT_ENTRY_LDT, \
.io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \
.io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \
}
static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
{
tss->esp0 = thread->esp0;
/* This can only happen when SEP is enabled, no need to test "SEP"arately */
if (unlikely(tss->ss1 != thread->sysenter_cs)) {
tss->ss1 = thread->sysenter_cs;
wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
}
HYPERVISOR_stack_switch(tss->ss0, tss->esp0);
}
#define start_thread(regs, new_eip, new_esp) do { \
__asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
set_fs(USER_DS); \
regs->xds = __USER_DS; \
regs->xes = __USER_DS; \
regs->xss = __USER_DS; \
regs->xcs = __USER_CS; \
regs->eip = new_eip; \
regs->esp = new_esp; \
} while (0)
/* Forward declaration, a strange C thing */
struct task_struct;
struct mm_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
/* Prepare to copy thread state - unlazy all lazy status */
extern void prepare_to_copy(struct task_struct *tsk);
/*
* create a kernel thread without removing it from tasklists
*/
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long thread_saved_pc(struct task_struct *tsk);
void show_trace(struct task_struct *task, unsigned long *stack);
unsigned long get_wchan(struct task_struct *p);
#define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long))
#define KSTK_TOP(info) \
({ \
unsigned long *__ptr = (unsigned long *)(info); \
(unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \
})
#define task_pt_regs(task) \
({ \
struct pt_regs *__regs__; \
__regs__ = (struct pt_regs *)KSTK_TOP((task)->thread_info); \
__regs__ - 1; \
})
#define KSTK_EIP(task) (task_pt_regs(task)->eip)
#define KSTK_ESP(task) (task_pt_regs(task)->esp)
struct microcode_header {
unsigned int hdrver;
unsigned int rev;
unsigned int date;
unsigned int sig;
unsigned int cksum;
unsigned int ldrver;
unsigned int pf;
unsigned int datasize;
unsigned int totalsize;
unsigned int reserved[3];
};
struct microcode {
struct microcode_header hdr;
unsigned int bits[0];
};
typedef struct microcode microcode_t;
typedef struct microcode_header microcode_header_t;
/* microcode format is extended from prescott processors */
struct extended_signature {
unsigned int sig;
unsigned int pf;
unsigned int cksum;
};
struct extended_sigtable {
unsigned int count;
unsigned int cksum;
unsigned int reserved[3];
struct extended_signature sigs[0];
};
/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
#define MICROCODE_IOCFREE _IO('6',0)
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
static inline void rep_nop(void)
{
__asm__ __volatile__("rep;nop": : :"memory");
}
#define cpu_relax() rep_nop()
/* generic versions from gas */
#define GENERIC_NOP1 ".byte 0x90\n"
#define GENERIC_NOP2 ".byte 0x89,0xf6\n"
#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n"
#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n"
#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4
#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7
/* Opteron nops */
#define K8_NOP1 GENERIC_NOP1
#define K8_NOP2 ".byte 0x66,0x90\n"
#define K8_NOP3 ".byte 0x66,0x66,0x90\n"
#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"
#define K8_NOP5 K8_NOP3 K8_NOP2
#define K8_NOP6 K8_NOP3 K8_NOP3
#define K8_NOP7 K8_NOP4 K8_NOP3
#define K8_NOP8 K8_NOP4 K8_NOP4
/* K7 nops */
/* uses eax dependencies (arbitary choice) */
#define K7_NOP1 GENERIC_NOP1
#define K7_NOP2 ".byte 0x8b,0xc0\n"
#define K7_NOP3 ".byte 0x8d,0x04,0x20\n"
#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n"
#define K7_NOP5 K7_NOP4 ASM_NOP1
#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n"
#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n"
#define K7_NOP8 K7_NOP7 ASM_NOP1
#ifdef CONFIG_MK8
#define ASM_NOP1 K8_NOP1
#define ASM_NOP2 K8_NOP2
#define ASM_NOP3 K8_NOP3
#define ASM_NOP4 K8_NOP4
#define ASM_NOP5 K8_NOP5
#define ASM_NOP6 K8_NOP6
#define ASM_NOP7 K8_NOP7
#define ASM_NOP8 K8_NOP8
#elif defined(CONFIG_MK7)
#define ASM_NOP1 K7_NOP1
#define ASM_NOP2 K7_NOP2
#define ASM_NOP3 K7_NOP3
#define ASM_NOP4 K7_NOP4
#define ASM_NOP5 K7_NOP5
#define ASM_NOP6 K7_NOP6
#define ASM_NOP7 K7_NOP7
#define ASM_NOP8 K7_NOP8
#else
#define ASM_NOP1 GENERIC_NOP1
#define ASM_NOP2 GENERIC_NOP2
#define ASM_NOP3 GENERIC_NOP3
#define ASM_NOP4 GENERIC_NOP4
#define ASM_NOP5 GENERIC_NOP5
#define ASM_NOP6 GENERIC_NOP6
#define ASM_NOP7 GENERIC_NOP7
#define ASM_NOP8 GENERIC_NOP8
#endif
#define ASM_NOP_MAX 8
/* Prefetch instructions for Pentium III and AMD Athlon */
/* It's not worth to care about 3dnow! prefetches for the K6
because they are microcoded there and very slow.
However we don't do prefetches for pre XP Athlons currently
That should be fixed. */
#define ARCH_HAS_PREFETCH
extern inline void prefetch(const void *x)
{
alternative_input(ASM_NOP4,
"prefetchnta (%1)",
X86_FEATURE_XMM,
"r" (x));
}
#define ARCH_HAS_PREFETCH
#define ARCH_HAS_PREFETCHW
#define ARCH_HAS_SPINLOCK_PREFETCH
/* 3dnow! prefetch to get an exclusive cache line. Useful for
spinlocks to avoid one state transition in the cache coherency protocol. */
extern inline void prefetchw(const void *x)
{
alternative_input(ASM_NOP4,
"prefetchw (%1)",
X86_FEATURE_3DNOW,
"r" (x));
}
#define spin_lock_prefetch(x) prefetchw(x)
extern void select_idle_routine(const struct cpuinfo_x86 *c);
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
#ifdef CONFIG_SCHED_SMT
#define ARCH_HAS_SCHED_DOMAIN
#define ARCH_HAS_SCHED_WAKE_IDLE
#endif
#endif /* __ASM_I386_PROCESSOR_H */
@@ -0,0 +1,62 @@
#ifndef _I386_PTRACE_H
#define _I386_PTRACE_H
#define EBX 0
#define ECX 1
#define EDX 2
#define ESI 3
#define EDI 4
#define EBP 5
#define EAX 6
#define DS 7
#define ES 8
#define FS 9
#define GS 10
#define ORIG_EAX 11
#define EIP 12
#define CS 13
#define EFL 14
#define UESP 15
#define SS 16
#define FRAME_SIZE 17
/* this struct defines the way the registers are stored on the
stack during a system call. */
struct pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
/* 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
#define PTRACE_OLDSETOPTIONS 21
#define PTRACE_GET_THREAD_AREA 25
#define PTRACE_SET_THREAD_AREA 26
#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (2 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip)
#endif
#endif
@@ -0,0 +1,96 @@
#ifndef _ASM_SEGMENT_H
#define _ASM_SEGMENT_H
/*
* The layout of the per-CPU GDT under Linux:
*
* 0 - null
* 1 - reserved
* 2 - reserved
* 3 - reserved
*
* 4 - unused <==== new cacheline
* 5 - unused
*
* ------- start of TLS (Thread-Local Storage) segments:
*
* 6 - TLS segment #1 [ glibc's TLS segment ]
* 7 - TLS segment #2 [ Wine's %fs Win32 segment ]
* 8 - TLS segment #3
* 9 - reserved
* 10 - reserved
* 11 - reserved
*
* ------- start of kernel segments:
*
* 12 - kernel code segment <==== new cacheline
* 13 - kernel data segment
* 14 - default user CS
* 15 - default user DS
* 16 - TSS
* 17 - LDT
* 18 - PNPBIOS support (16->32 gate)
* 19 - PNPBIOS support
* 20 - PNPBIOS support
* 21 - PNPBIOS support
* 22 - PNPBIOS support
* 23 - APM BIOS support
* 24 - APM BIOS support
* 25 - APM BIOS support
*
* 26 - unused
* 27 - unused
* 28 - unused
* 29 - unused
* 30 - unused
* 31 - TSS for double fault handler
*/
#define GDT_ENTRY_TLS_ENTRIES 3
#define GDT_ENTRY_TLS_MIN 6
#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
#define GDT_ENTRY_DEFAULT_USER_CS 14
#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)
#define GDT_ENTRY_DEFAULT_USER_DS 15
#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)
#define GDT_ENTRY_KERNEL_BASE 12
#define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0)
#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8 + 1)
#define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1)
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8 + 1)
#define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4)
#define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5)
#define GDT_ENTRY_PNPBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 6)
#define GDT_ENTRY_APMBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 11)
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
/*
* The GDT has LAST_RESERVED_GDT_ENTRY + 1 entries
*/
#define GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY + 1)
#define GDT_SIZE (GDT_ENTRIES * 8)
/* Simple and small GDT entries for booting only */
#define __BOOT_CS FLAT_GUESTOS_CS
#define __BOOT_DS FLAT_GUESTOS_DS
/*
* The interrupt descriptor table has room for 256 idt's,
* the global descriptor table is dependent on the number
* of tasks we can have..
*/
#define IDT_ENTRIES 256
#endif
@@ -0,0 +1,65 @@
/*
* Just a place holder. We don't want to have to test x86 before
* we include stuff
*/
#ifndef _i386_SETUP_H
#define _i386_SETUP_H
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
/*
* Reserved space for vmalloc and iomap - defined in asm/page.h
*/
#define MAXMEM_PFN PFN_DOWN(MAXMEM)
#define MAX_NONPAE_PFN (1 << 20)
#define PARAM_SIZE 2048
#define COMMAND_LINE_SIZE 256
#define OLD_CL_MAGIC_ADDR 0x90020
#define OLD_CL_MAGIC 0xA33F
#define OLD_CL_BASE_ADDR 0x90000
#define OLD_CL_OFFSET 0x90022
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
#ifndef __ASSEMBLY__
/*
* This is set up by the setup-routine at boot-time
*/
extern unsigned char boot_params[PARAM_SIZE];
#define PARAM (boot_params)
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
#define ALT_MEM_K (*(unsigned long *) (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 IST_INFO (*(struct ist_info *) (PARAM+0x60))
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0)))
#define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define 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 long *) (PARAM+0x214))
#define INITRD_START (start_info.mod_start)
#define INITRD_SIZE (start_info.mod_len)
#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
#define DISK80_SIGNATURE (*(unsigned int*) (PARAM+DISK80_SIG_BUFFER))
#define EDD_NR (*(unsigned char *) (PARAM+EDDNR))
#define EDD_BUF ((struct edd_info *) (PARAM+EDDBUF))
#endif /* __ASSEMBLY__ */
#endif /* _i386_SETUP_H */
@@ -0,0 +1,83 @@
#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.
*/
#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,525 @@
#ifndef __ASM_SYSTEM_H
#define __ASM_SYSTEM_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <asm/synch_bitops.h>
#include <asm/segment.h>
#include <asm/cpufeature.h>
#include <asm/hypervisor.h>
#include <asm-xen/evtchn.h>
#ifdef __KERNEL__
struct task_struct; /* one of the stranger aspects of C forward declarations.. */
extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
#define switch_to(prev,next,last) do { \
unsigned long esi,edi; \
asm volatile("pushfl\n\t" \
"pushl %%ebp\n\t" \
"movl %%esp,%0\n\t" /* save ESP */ \
"movl %5,%%esp\n\t" /* restore ESP */ \
"movl $1f,%1\n\t" /* save EIP */ \
"pushl %6\n\t" /* restore EIP */ \
"jmp __switch_to\n" \
"1:\t" \
"popl %%ebp\n\t" \
"popfl" \
:"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=a" (last),"=S" (esi),"=D" (edi) \
:"m" (next->thread.esp),"m" (next->thread.eip), \
"2" (prev), "d" (next)); \
} while (0)
#define _set_base(addr,base) do { unsigned long __pr; \
__asm__ __volatile__ ("movw %%dx,%1\n\t" \
"rorl $16,%%edx\n\t" \
"movb %%dl,%2\n\t" \
"movb %%dh,%3" \
:"=&d" (__pr) \
:"m" (*((addr)+2)), \
"m" (*((addr)+4)), \
"m" (*((addr)+7)), \
"0" (base) \
); } while(0)
#define _set_limit(addr,limit) do { unsigned long __lr; \
__asm__ __volatile__ ("movw %%dx,%1\n\t" \
"rorl $16,%%edx\n\t" \
"movb %2,%%dh\n\t" \
"andb $0xf0,%%dh\n\t" \
"orb %%dh,%%dl\n\t" \
"movb %%dl,%2" \
:"=&d" (__lr) \
:"m" (*(addr)), \
"m" (*((addr)+6)), \
"0" (limit) \
); } while(0)
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
static inline unsigned long _get_base(char * addr)
{
unsigned long __base;
__asm__("movb %3,%%dh\n\t"
"movb %2,%%dl\n\t"
"shll $16,%%edx\n\t"
"movw %1,%%dx"
:"=&d" (__base)
:"m" (*((addr)+2)),
"m" (*((addr)+4)),
"m" (*((addr)+7)));
return __base;
}
#define get_base(ldt) _get_base( ((char *)&(ldt)) )
/*
* Load a segment. Fall back on loading the zero
* segment if something goes wrong..
*/
#define loadsegment(seg,value) \
asm volatile("\n" \
"1:\t" \
"movl %0,%%" #seg "\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3:\t" \
"pushl $0\n\t" \
"popl %%" #seg "\n\t" \
"jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n\t" \
".align 4\n\t" \
".long 1b,3b\n" \
".previous" \
: :"m" (*(unsigned int *)&(value)))
/*
* Save a segment register away
*/
#define savesegment(seg, value) \
asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
/*
* Clear and set 'TS' bit respectively
*/
/* NB. 'clts' is done for us by Xen during virtual trap. */
#define clts() ((void)0)
#define read_cr0() \
BUG();
#define write_cr0(x) \
BUG();
#define read_cr4() \
BUG();
#define write_cr4(x) \
BUG();
#define stts() (HYPERVISOR_fpu_taskswitch())
#endif /* __KERNEL__ */
#define wbinvd() \
BUG();
// __asm__ __volatile__ ("wbinvd": : :"memory");
static inline unsigned long get_limit(unsigned long segment)
{
unsigned long __limit;
__asm__("lsll %1,%0"
:"=r" (__limit):"r" (segment));
return __limit+1;
}
#define nop() __asm__ __volatile__ ("nop")
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
#define tas(ptr) (xchg((ptr),1))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
/*
* The semantics of XCHGCMP8B are a bit strange, this is why
* there is a loop and the loading of %%eax and %%edx has to
* be inside. This inlines well in most cases, the cached
* cost is around ~38 cycles. (in the future we might want
* to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
* might have an implicit FPU-save as a cost, so it's not
* clear which path to go.)
*
* cmpxchg8b must be used with the lock prefix here to allow
* the instruction to be executed atomically, see page 3-102
* of the instruction set reference 24319102.pdf. We need
* the reader side to see the coherent 64bit value.
*/
static inline void __set_64bit (unsigned long long * ptr,
unsigned int low, unsigned int high)
{
__asm__ __volatile__ (
"\n1:\t"
"movl (%0), %%eax\n\t"
"movl 4(%0), %%edx\n\t"
"lock cmpxchg8b (%0)\n\t"
"jnz 1b"
: /* no outputs */
: "D"(ptr),
"b"(low),
"c"(high)
: "ax","dx","memory");
}
static inline void __set_64bit_constant (unsigned long long *ptr,
unsigned long long value)
{
__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
}
#define ll_low(x) *(((unsigned int*)&(x))+0)
#define ll_high(x) *(((unsigned int*)&(x))+1)
static inline void __set_64bit_var (unsigned long long *ptr,
unsigned long long value)
{
__set_64bit(ptr,ll_low(value), ll_high(value));
}
#define set_64bit(ptr,value) \
(__builtin_constant_p(value) ? \
__set_64bit_constant(ptr, value) : \
__set_64bit_var(ptr, value) )
#define _set_64bit(ptr,value) \
(__builtin_constant_p(value) ? \
__set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
__set_64bit(ptr, ll_low(value), ll_high(value)) )
/*
* 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 %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.
*/
#ifdef CONFIG_X86_CMPXCHG
#define __HAVE_ARCH_CMPXCHG 1
#endif
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 %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 __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;
};
#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 4\n" \
" .long 661b\n" /* label */ \
" .long 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 4\n" \
" .long 661b\n" /* label */ \
" .long 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)
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
* to devices.
*
* For now, "wmb()" doesn't actually do anything, as all
* Intel CPU's follow what Intel calls a *Processor Order*,
* in which all writes are seen in the program order even
* outside the CPU.
*
* I expect future Intel CPU's to have a weaker ordering,
* but I'd also expect them to finally get their act together
* and add some real memory barriers if so.
*
* Some non intel clones support out of order store. wmb() ceases to be a
* nop for these.
*/
/*
* Actually only lfence would be needed for mb() because all stores done
* by the kernel should be already ordered. But keep a full barrier for now.
*/
#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
/**
* read_barrier_depends - Flush all pending reads that subsequents reads
* depend on.
*
* No data-dependent reads from memory-like regions are ever reordered
* over this barrier. All reads preceding this primitive are guaranteed
* to access memory (but not necessarily other CPUs' caches) before any
* reads following this primitive that depend on the data return by
* any of the preceding reads. This primitive is much lighter weight than
* rmb() on most CPUs, and is never heavier weight than is
* rmb().
*
* These ordering constraints are respected by both the local CPU
* and the compiler.
*
* Ordering is not guaranteed by anything other than these primitives,
* not even by data dependencies. See the documentation for
* memory_barrier() for examples and URLs to more information.
*
* For example, the following code would force ordering (the initial
* value of "a" is zero, "b" is one, and "p" is "&a"):
*
* <programlisting>
* CPU 0 CPU 1
*
* b = 2;
* memory_barrier();
* p = &b; q = p;
* read_barrier_depends();
* d = *q;
* </programlisting>
*
* because the read of "*q" depends on the read of "p" and these
* two reads are separated by a read_barrier_depends(). However,
* the following code, with the same initial values for "a" and "b":
*
* <programlisting>
* CPU 0 CPU 1
*
* a = 2;
* memory_barrier();
* b = 3; y = b;
* read_barrier_depends();
* x = a;
* </programlisting>
*
* does not enforce ordering, since there is no data dependency between
* the read of "a" and the read of "b". Therefore, on some CPUs, such
* as Alpha, "y" could be set to 3 and "x" to 0. Use rmb()
* in cases like thiswhere there are no data dependencies.
**/
#define read_barrier_depends() do { } while(0)
#ifdef CONFIG_X86_OOSTORE
/* Actually there are no OOO store capable CPUs for now that do SSE,
but make it already an possibility. */
#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
#else
#define wmb() __asm__ __volatile__ ("": : :"memory")
#endif
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
/* interrupt control.. */
/*
* 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 operatiosn must complete
* /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
* includes these barriers, for example.
*/
#define __cli() \
do { \
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \
barrier(); \
} while (0)
#define __sti() \
do { \
shared_info_t *_shared = HYPERVISOR_shared_info; \
barrier(); \
_shared->vcpu_data[0].evtchn_upcall_mask = 0; \
barrier(); /* unmask then check (avoid races) */ \
if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
evtchn_do_upcall(NULL); \
} while (0)
#define __save_flags(x) \
do { \
(x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \
} while (0)
#define __restore_flags(x) \
do { \
shared_info_t *_shared = HYPERVISOR_shared_info; \
barrier(); \
if ( (_shared->vcpu_data[0].evtchn_upcall_mask = (x)) == 0 ) { \
barrier(); /* unmask then check (avoid races) */ \
if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
evtchn_do_upcall(NULL); \
} \
} while (0)
#define safe_halt() ((void)0)
#define __save_and_cli(x) \
do { \
(x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \
barrier(); \
} while (0)
#define __save_and_sti(x) \
do { \
shared_info_t *_shared = HYPERVISOR_shared_info; \
barrier(); \
(x) = _shared->vcpu_data[0].evtchn_upcall_mask; \
_shared->vcpu_data[0].evtchn_upcall_mask = 0; \
barrier(); /* unmask then check (avoid races) */ \
if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
evtchn_do_upcall(NULL); \
} while (0)
#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[0].evtchn_upcall_mask
/*
* disable hlt during certain critical i/o operations
*/
#define HAVE_DISABLE_HLT
void disable_hlt(void);
void enable_hlt(void);
extern unsigned long dmi_broken;
extern int is_sony_vaio_laptop;
extern int es7000_plat;
#define BROKEN_ACPI_Sx 0x0001
#define BROKEN_INIT_AFTER_S1 0x0002
#define BROKEN_PNP_BIOS 0x0004
#define BROKEN_CPUFREQ 0x0008
#endif
@@ -0,0 +1,58 @@
#ifndef _ASMi386_TIMER_H
#define _ASMi386_TIMER_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;
int (*init)(char *override);
void (*mark_offset)(void);
unsigned long (*get_offset)(void);
unsigned long long (*monotonic_clock)(void);
void (*delay)(unsigned long);
};
#define TICK_SIZE (tick_nsec / 1000)
extern struct timer_opts* select_timer(void);
extern void clock_fallback(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 timer_opts timer_tsc;
#ifdef CONFIG_X86_CYCLONE_TIMER
extern struct timer_opts timer_cyclone;
#endif
extern struct timer_opts timer_xen;
extern unsigned long calibrate_tsc(void);
extern void init_cpu_khz(void);
#ifdef CONFIG_HPET_TIMER
extern struct timer_opts timer_hpet;
extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
#endif
#ifdef CONFIG_X86_PM_TIMER
extern struct timer_opts timer_pmtmr;
#endif
#endif
@@ -0,0 +1,133 @@
#ifndef _I386_TLBFLUSH_H
#define _I386_TLBFLUSH_H
#include <linux/config.h>
#include <linux/mm.h>
#include <asm/processor.h>
#define __flush_tlb() do { \
queue_tlb_flush(); \
xen_flush_page_update_queue(); \
} while (/*CONSTCOND*/0)
/*
* Global pages have to be flushed a bit differently. Not a real
* performance problem because this does not happen often.
*/
#define __flush_tlb_global() \
do { \
unsigned int tmpreg; \
\
__asm__ __volatile__( \
"movl %1, %%cr4; # turn off PGE \n" \
"movl %%cr3, %0; \n" \
"movl %0, %%cr3; # flush TLB \n" \
"movl %2, %%cr4; # turn PGE back on \n" \
: "=&r" (tmpreg) \
: "r" (mmu_cr4_features & ~X86_CR4_PGE), \
"r" (mmu_cr4_features) \
: "memory"); \
} while (0)
extern unsigned long pgkern_mask;
# define __flush_tlb_all() \
do { \
if (cpu_has_pge) \
__flush_tlb_global(); \
else \
__flush_tlb(); \
} while (0)
#define cpu_has_invlpg (boot_cpu_data.x86 > 3)
#define __flush_tlb_single(addr) do { \
queue_invlpg(addr); \
xen_flush_page_update_queue(); \
} while (/* CONSTCOND */0)
# define __flush_tlb_one(addr) __flush_tlb_single(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 i386 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
struct tlb_state
{
struct mm_struct *active_mm;
int state;
char __cacheline_padding[L1_CACHE_BYTES-8];
};
extern struct tlb_state cpu_tlbstate[NR_CPUS];
#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)
{
/* i386 does not keep any page table caches in TLB */
}
#endif /* _I386_TLBFLUSH_H */
@@ -0,0 +1,884 @@
/*
* include/asm-i386/xor.h
*
* Optimized RAID-5 checksumming functions for MMX and SSE.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example /usr/src/linux/COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* High-speed RAID5 checksumming functions utilizing MMX instructions.
* Copyright (C) 1998 Ingo Molnar.
*/
#define LD(x,y) " movq 8*("#x")(%1), %%mm"#y" ;\n"
#define ST(x,y) " movq %%mm"#y", 8*("#x")(%1) ;\n"
#define XO1(x,y) " pxor 8*("#x")(%2), %%mm"#y" ;\n"
#define XO2(x,y) " pxor 8*("#x")(%3), %%mm"#y" ;\n"
#define XO3(x,y) " pxor 8*("#x")(%4), %%mm"#y" ;\n"
#define XO4(x,y) " pxor 8*("#x")(%5), %%mm"#y" ;\n"
#include <asm/i387.h>
static void
xor_pII_mmx_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
{
unsigned long lines = bytes >> 7;
kernel_fpu_begin();
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
XO1(i,0) \
ST(i,0) \
XO1(i+1,1) \
ST(i+1,1) \
XO1(i+2,2) \
ST(i+2,2) \
XO1(i+3,3) \
ST(i+3,3)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addl $128, %1 ;\n"
" addl $128, %2 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2)
:
: "memory");
kernel_fpu_end();
}
static void
xor_pII_mmx_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3)
{
unsigned long lines = bytes >> 7;
kernel_fpu_begin();
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
XO1(i,0) \
XO1(i+1,1) \
XO1(i+2,2) \
XO1(i+3,3) \
XO2(i,0) \
ST(i,0) \
XO2(i+1,1) \
ST(i+1,1) \
XO2(i+2,2) \
ST(i+2,2) \
XO2(i+3,3) \
ST(i+3,3)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addl $128, %1 ;\n"
" addl $128, %2 ;\n"
" addl $128, %3 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3)
:
: "memory");
kernel_fpu_end();
}
static void
xor_pII_mmx_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4)
{
unsigned long lines = bytes >> 7;
kernel_fpu_begin();
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
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) \
XO3(i,0) \
ST(i,0) \
XO3(i+1,1) \
ST(i+1,1) \
XO3(i+2,2) \
ST(i+2,2) \
XO3(i+3,3) \
ST(i+3,3)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addl $128, %1 ;\n"
" addl $128, %2 ;\n"
" addl $128, %3 ;\n"
" addl $128, %4 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4)
:
: "memory");
kernel_fpu_end();
}
static void
xor_pII_mmx_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4, unsigned long *p5)
{
unsigned long lines = bytes >> 7;
kernel_fpu_begin();
/* Make sure GCC forgets anything it knows about p4 or p5,
such that it won't pass to the asm volatile below a
register that is shared with any other variable. That's
because we modify p4 and p5 there, but we can't mark them
as read/write, otherwise we'd overflow the 10-asm-operands
limit of GCC < 3.1. */
__asm__ ("" : "+r" (p4), "+r" (p5));
__asm__ __volatile__ (
#undef BLOCK
#define BLOCK(i) \
LD(i,0) \
LD(i+1,1) \
LD(i+2,2) \
LD(i+3,3) \
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) \
XO3(i,0) \
XO3(i+1,1) \
XO3(i+2,2) \
XO3(i+3,3) \
XO4(i,0) \
ST(i,0) \
XO4(i+1,1) \
ST(i+1,1) \
XO4(i+2,2) \
ST(i+2,2) \
XO4(i+3,3) \
ST(i+3,3)
" .align 32 ;\n"
" 1: ;\n"
BLOCK(0)
BLOCK(4)
BLOCK(8)
BLOCK(12)
" addl $128, %1 ;\n"
" addl $128, %2 ;\n"
" addl $128, %3 ;\n"
" addl $128, %4 ;\n"
" addl $128, %5 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3)
: "r" (p4), "r" (p5)
: "memory");
/* p4 and p5 were modified, and now the variables are dead.
Clobber them just to be sure nobody does something stupid
like assuming they have some legal value. */
__asm__ ("" : "=r" (p4), "=r" (p5));
kernel_fpu_end();
}
#undef LD
#undef XO1
#undef XO2
#undef XO3
#undef XO4
#undef ST
#undef BLOCK
static void
xor_p5_mmx_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
{
unsigned long lines = bytes >> 6;
kernel_fpu_begin();
__asm__ __volatile__ (
" .align 32 ;\n"
" 1: ;\n"
" movq (%1), %%mm0 ;\n"
" movq 8(%1), %%mm1 ;\n"
" pxor (%2), %%mm0 ;\n"
" movq 16(%1), %%mm2 ;\n"
" movq %%mm0, (%1) ;\n"
" pxor 8(%2), %%mm1 ;\n"
" movq 24(%1), %%mm3 ;\n"
" movq %%mm1, 8(%1) ;\n"
" pxor 16(%2), %%mm2 ;\n"
" movq 32(%1), %%mm4 ;\n"
" movq %%mm2, 16(%1) ;\n"
" pxor 24(%2), %%mm3 ;\n"
" movq 40(%1), %%mm5 ;\n"
" movq %%mm3, 24(%1) ;\n"
" pxor 32(%2), %%mm4 ;\n"
" movq 48(%1), %%mm6 ;\n"
" movq %%mm4, 32(%1) ;\n"
" pxor 40(%2), %%mm5 ;\n"
" movq 56(%1), %%mm7 ;\n"
" movq %%mm5, 40(%1) ;\n"
" pxor 48(%2), %%mm6 ;\n"
" pxor 56(%2), %%mm7 ;\n"
" movq %%mm6, 48(%1) ;\n"
" movq %%mm7, 56(%1) ;\n"
" addl $64, %1 ;\n"
" addl $64, %2 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2)
:
: "memory");
kernel_fpu_end();
}
static void
xor_p5_mmx_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3)
{
unsigned long lines = bytes >> 6;
kernel_fpu_begin();
__asm__ __volatile__ (
" .align 32,0x90 ;\n"
" 1: ;\n"
" movq (%1), %%mm0 ;\n"
" movq 8(%1), %%mm1 ;\n"
" pxor (%2), %%mm0 ;\n"
" movq 16(%1), %%mm2 ;\n"
" pxor 8(%2), %%mm1 ;\n"
" pxor (%3), %%mm0 ;\n"
" pxor 16(%2), %%mm2 ;\n"
" movq %%mm0, (%1) ;\n"
" pxor 8(%3), %%mm1 ;\n"
" pxor 16(%3), %%mm2 ;\n"
" movq 24(%1), %%mm3 ;\n"
" movq %%mm1, 8(%1) ;\n"
" movq 32(%1), %%mm4 ;\n"
" movq 40(%1), %%mm5 ;\n"
" pxor 24(%2), %%mm3 ;\n"
" movq %%mm2, 16(%1) ;\n"
" pxor 32(%2), %%mm4 ;\n"
" pxor 24(%3), %%mm3 ;\n"
" pxor 40(%2), %%mm5 ;\n"
" movq %%mm3, 24(%1) ;\n"
" pxor 32(%3), %%mm4 ;\n"
" pxor 40(%3), %%mm5 ;\n"
" movq 48(%1), %%mm6 ;\n"
" movq %%mm4, 32(%1) ;\n"
" movq 56(%1), %%mm7 ;\n"
" pxor 48(%2), %%mm6 ;\n"
" movq %%mm5, 40(%1) ;\n"
" pxor 56(%2), %%mm7 ;\n"
" pxor 48(%3), %%mm6 ;\n"
" pxor 56(%3), %%mm7 ;\n"
" movq %%mm6, 48(%1) ;\n"
" movq %%mm7, 56(%1) ;\n"
" addl $64, %1 ;\n"
" addl $64, %2 ;\n"
" addl $64, %3 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3)
:
: "memory" );
kernel_fpu_end();
}
static void
xor_p5_mmx_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4)
{
unsigned long lines = bytes >> 6;
kernel_fpu_begin();
__asm__ __volatile__ (
" .align 32,0x90 ;\n"
" 1: ;\n"
" movq (%1), %%mm0 ;\n"
" movq 8(%1), %%mm1 ;\n"
" pxor (%2), %%mm0 ;\n"
" movq 16(%1), %%mm2 ;\n"
" pxor 8(%2), %%mm1 ;\n"
" pxor (%3), %%mm0 ;\n"
" pxor 16(%2), %%mm2 ;\n"
" pxor 8(%3), %%mm1 ;\n"
" pxor (%4), %%mm0 ;\n"
" movq 24(%1), %%mm3 ;\n"
" pxor 16(%3), %%mm2 ;\n"
" pxor 8(%4), %%mm1 ;\n"
" movq %%mm0, (%1) ;\n"
" movq 32(%1), %%mm4 ;\n"
" pxor 24(%2), %%mm3 ;\n"
" pxor 16(%4), %%mm2 ;\n"
" movq %%mm1, 8(%1) ;\n"
" movq 40(%1), %%mm5 ;\n"
" pxor 32(%2), %%mm4 ;\n"
" pxor 24(%3), %%mm3 ;\n"
" movq %%mm2, 16(%1) ;\n"
" pxor 40(%2), %%mm5 ;\n"
" pxor 32(%3), %%mm4 ;\n"
" pxor 24(%4), %%mm3 ;\n"
" movq %%mm3, 24(%1) ;\n"
" movq 56(%1), %%mm7 ;\n"
" movq 48(%1), %%mm6 ;\n"
" pxor 40(%3), %%mm5 ;\n"
" pxor 32(%4), %%mm4 ;\n"
" pxor 48(%2), %%mm6 ;\n"
" movq %%mm4, 32(%1) ;\n"
" pxor 56(%2), %%mm7 ;\n"
" pxor 40(%4), %%mm5 ;\n"
" pxor 48(%3), %%mm6 ;\n"
" pxor 56(%3), %%mm7 ;\n"
" movq %%mm5, 40(%1) ;\n"
" pxor 48(%4), %%mm6 ;\n"
" pxor 56(%4), %%mm7 ;\n"
" movq %%mm6, 48(%1) ;\n"
" movq %%mm7, 56(%1) ;\n"
" addl $64, %1 ;\n"
" addl $64, %2 ;\n"
" addl $64, %3 ;\n"
" addl $64, %4 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4)
:
: "memory");
kernel_fpu_end();
}
static void
xor_p5_mmx_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4, unsigned long *p5)
{
unsigned long lines = bytes >> 6;
kernel_fpu_begin();
/* Make sure GCC forgets anything it knows about p4 or p5,
such that it won't pass to the asm volatile below a
register that is shared with any other variable. That's
because we modify p4 and p5 there, but we can't mark them
as read/write, otherwise we'd overflow the 10-asm-operands
limit of GCC < 3.1. */
__asm__ ("" : "+r" (p4), "+r" (p5));
__asm__ __volatile__ (
" .align 32,0x90 ;\n"
" 1: ;\n"
" movq (%1), %%mm0 ;\n"
" movq 8(%1), %%mm1 ;\n"
" pxor (%2), %%mm0 ;\n"
" pxor 8(%2), %%mm1 ;\n"
" movq 16(%1), %%mm2 ;\n"
" pxor (%3), %%mm0 ;\n"
" pxor 8(%3), %%mm1 ;\n"
" pxor 16(%2), %%mm2 ;\n"
" pxor (%4), %%mm0 ;\n"
" pxor 8(%4), %%mm1 ;\n"
" pxor 16(%3), %%mm2 ;\n"
" movq 24(%1), %%mm3 ;\n"
" pxor (%5), %%mm0 ;\n"
" pxor 8(%5), %%mm1 ;\n"
" movq %%mm0, (%1) ;\n"
" pxor 16(%4), %%mm2 ;\n"
" pxor 24(%2), %%mm3 ;\n"
" movq %%mm1, 8(%1) ;\n"
" pxor 16(%5), %%mm2 ;\n"
" pxor 24(%3), %%mm3 ;\n"
" movq 32(%1), %%mm4 ;\n"
" movq %%mm2, 16(%1) ;\n"
" pxor 24(%4), %%mm3 ;\n"
" pxor 32(%2), %%mm4 ;\n"
" movq 40(%1), %%mm5 ;\n"
" pxor 24(%5), %%mm3 ;\n"
" pxor 32(%3), %%mm4 ;\n"
" pxor 40(%2), %%mm5 ;\n"
" movq %%mm3, 24(%1) ;\n"
" pxor 32(%4), %%mm4 ;\n"
" pxor 40(%3), %%mm5 ;\n"
" movq 48(%1), %%mm6 ;\n"
" movq 56(%1), %%mm7 ;\n"
" pxor 32(%5), %%mm4 ;\n"
" pxor 40(%4), %%mm5 ;\n"
" pxor 48(%2), %%mm6 ;\n"
" pxor 56(%2), %%mm7 ;\n"
" movq %%mm4, 32(%1) ;\n"
" pxor 48(%3), %%mm6 ;\n"
" pxor 56(%3), %%mm7 ;\n"
" pxor 40(%5), %%mm5 ;\n"
" pxor 48(%4), %%mm6 ;\n"
" pxor 56(%4), %%mm7 ;\n"
" movq %%mm5, 40(%1) ;\n"
" pxor 48(%5), %%mm6 ;\n"
" pxor 56(%5), %%mm7 ;\n"
" movq %%mm6, 48(%1) ;\n"
" movq %%mm7, 56(%1) ;\n"
" addl $64, %1 ;\n"
" addl $64, %2 ;\n"
" addl $64, %3 ;\n"
" addl $64, %4 ;\n"
" addl $64, %5 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3)
: "r" (p4), "r" (p5)
: "memory");
/* p4 and p5 were modified, and now the variables are dead.
Clobber them just to be sure nobody does something stupid
like assuming they have some legal value. */
__asm__ ("" : "=r" (p4), "=r" (p5));
kernel_fpu_end();
}
static struct xor_block_template xor_block_pII_mmx = {
.name = "pII_mmx",
.do_2 = xor_pII_mmx_2,
.do_3 = xor_pII_mmx_3,
.do_4 = xor_pII_mmx_4,
.do_5 = xor_pII_mmx_5,
};
static struct xor_block_template xor_block_p5_mmx = {
.name = "p5_mmx",
.do_2 = xor_p5_mmx_2,
.do_3 = xor_p5_mmx_3,
.do_4 = xor_p5_mmx_4,
.do_5 = xor_p5_mmx_5,
};
/*
* Cache avoiding checksumming functions utilizing KNI instructions
* Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
*/
#define XMMS_SAVE do { \
preempt_disable(); \
if (!(current->flags & PF_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->flags & PF_USEDFPU)) \
stts(); \
preempt_enable(); \
} while(0)
#define ALIGN16 __attribute__((aligned(16)))
#define OFFS(x) "16*("#x")"
#define PF_OFFS(x) "256+16*("#x")"
#define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n"
#define LD(x,y) " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n"
#define ST(x,y) " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n"
#define PF1(x) " prefetchnta "PF_OFFS(x)"(%2) ;\n"
#define PF2(x) " prefetchnta "PF_OFFS(x)"(%3) ;\n"
#define PF3(x) " prefetchnta "PF_OFFS(x)"(%4) ;\n"
#define PF4(x) " prefetchnta "PF_OFFS(x)"(%5) ;\n"
#define PF5(x) " prefetchnta "PF_OFFS(x)"(%6) ;\n"
#define XO1(x,y) " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n"
#define XO2(x,y) " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n"
#define XO3(x,y) " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n"
#define XO4(x,y) " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n"
#define XO5(x,y) " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n"
static void
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
{
unsigned long lines = bytes >> 8;
char xmm_save[16*4] ALIGN16;
int cr0;
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)
" addl $256, %1 ;\n"
" addl $256, %2 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2)
:
: "memory");
XMMS_RESTORE;
}
static void
xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3)
{
unsigned long lines = bytes >> 8;
char xmm_save[16*4] ALIGN16;
int 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)
" addl $256, %1 ;\n"
" addl $256, %2 ;\n"
" addl $256, %3 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r"(p2), "+r"(p3)
:
: "memory" );
XMMS_RESTORE;
}
static void
xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
unsigned long *p3, unsigned long *p4)
{
unsigned long lines = bytes >> 8;
char xmm_save[16*4] ALIGN16;
int 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)
" addl $256, %1 ;\n"
" addl $256, %2 ;\n"
" addl $256, %3 ;\n"
" addl $256, %4 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4)
:
: "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 long lines = bytes >> 8;
char xmm_save[16*4] ALIGN16;
int cr0;
XMMS_SAVE;
/* Make sure GCC forgets anything it knows about p4 or p5,
such that it won't pass to the asm volatile below a
register that is shared with any other variable. That's
because we modify p4 and p5 there, but we can't mark them
as read/write, otherwise we'd overflow the 10-asm-operands
limit of GCC < 3.1. */
__asm__ ("" : "+r" (p4), "+r" (p5));
__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)
" addl $256, %1 ;\n"
" addl $256, %2 ;\n"
" addl $256, %3 ;\n"
" addl $256, %4 ;\n"
" addl $256, %5 ;\n"
" decl %0 ;\n"
" jnz 1b ;\n"
: "+r" (lines),
"+r" (p1), "+r" (p2), "+r" (p3)
: "r" (p4), "r" (p5)
: "memory");
/* p4 and p5 were modified, and now the variables are dead.
Clobber them just to be sure nobody does something stupid
like assuming they have some legal value. */
__asm__ ("" : "=r" (p4), "=r" (p5));
XMMS_RESTORE;
}
static struct xor_block_template xor_block_pIII_sse = {
.name = "pIII_sse",
.do_2 = xor_sse_2,
.do_3 = xor_sse_3,
.do_4 = xor_sse_4,
.do_5 = xor_sse_5,
};
/* Also try the generic routines. */
#include <asm-generic/xor.h>
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_8regs_p); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_32regs_p); \
if (cpu_has_xmm) \
xor_speed(&xor_block_pIII_sse); \
if (cpu_has_mmx) { \
xor_speed(&xor_block_pII_mmx); \
xor_speed(&xor_block_p5_mmx); \
} \
} 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) \
(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
@@ -0,0 +1,115 @@
/******************************************************************************
* blkif.h
*
* Unified block-device I/O interface for Xen guest OSes.
*
* Copyright (c) 2003-2004, Keir Fraser
*/
#ifndef __SHARED_BLKIF_H__
#define __SHARED_BLKIF_H__
#define blkif_vdev_t u16
#define blkif_sector_t u64
#define BLKIF_OP_READ 0
#define BLKIF_OP_WRITE 1
#define BLKIF_OP_PROBE 2
/* NB. Ring size must be small enough for sizeof(blkif_ring_t) <= PAGE_SIZE. */
#define BLKIF_RING_SIZE 64
/*
* Maximum scatter/gather segments per request.
* This is carefully chosen so that sizeof(blkif_ring_t) <= PAGE_SIZE.
* NB. This could be 12 if the ring indexes weren't stored in the same page.
*/
#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
typedef struct {
u8 operation; /* 0: BLKIF_OP_??? */
u8 nr_segments; /* 1: number of segments */
blkif_vdev_t device; /* 2: only for read/write requests */
unsigned long id; /* 4: private guest value, echoed in resp */
blkif_sector_t sector_number; /* start sector idx on disk (r/w only) */
/* @f_a_s[2:0]=last_sect ; @f_a_s[5:3]=first_sect ; @f_a_s[:12]=frame. */
/* @first_sect: first sector in frame to transfer (inclusive). */
/* @last_sect: last sector in frame to transfer (inclusive). */
/* @frame: machine page frame number. */
unsigned long frame_and_sects[BLKIF_MAX_SEGMENTS_PER_REQUEST];
} PACKED blkif_request_t;
#define blkif_first_sect(_fas) (((_fas)>>3)&7)
#define blkif_last_sect(_fas) ((_fas)&7)
typedef struct {
unsigned long id; /* copied from request */
u8 operation; /* copied from request */
s16 status; /* BLKIF_RSP_??? */
} PACKED blkif_response_t;
#define BLKIF_RSP_ERROR -1 /* non-specific 'error' */
#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
/*
* We use a special capitalised type name because it is _essential_ that all
* arithmetic on indexes is done on an integer type of the correct size.
*/
typedef u32 BLKIF_RING_IDX;
/*
* Ring indexes are 'free running'. That is, they are not stored modulo the
* size of the ring buffer. The following macro converts a free-running counter
* into a value that can directly index a ring-buffer array.
*/
#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1))
typedef struct {
BLKIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */
BLKIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */
union { /* 8 */
blkif_request_t req;
blkif_response_t resp;
} PACKED ring[BLKIF_RING_SIZE];
} PACKED blkif_ring_t;
/*
* BLKIF_OP_PROBE:
* The request format for a probe request is constrained as follows:
* @operation == BLKIF_OP_PROBE
* @nr_segments == size of probe buffer in pages
* @device == unused (zero)
* @id == any value (echoed in response message)
* @sector_num == unused (zero)
* @frame_and_sects == list of page-sized buffers.
* (i.e., @first_sect == 0, @last_sect == 7).
*
* The response is a list of vdisk_t elements copied into the out-of-band
* probe buffer. On success the response status field contains the number
* of vdisk_t elements.
*/
/* XXX SMH: Type values below are chosen to match ide_xxx in Linux ide.h. */
#define VDISK_TYPE_FLOPPY 0x00
#define VDISK_TYPE_TAPE 0x01
#define VDISK_TYPE_CDROM 0x05
#define VDISK_TYPE_OPTICAL 0x07
#define VDISK_TYPE_DISK 0x20
#define VDISK_TYPE_MASK 0x3F
#define VDISK_TYPE(_x) ((_x) & VDISK_TYPE_MASK)
/* The top two bits of the type field encode various flags. */
#define VDISK_FLAG_RO 0x40
#define VDISK_FLAG_VIRT 0x80
#define VDISK_READONLY(_x) ((_x) & VDISK_FLAG_RO)
#define VDISK_VIRTUAL(_x) ((_x) & VDISK_FLAG_VIRT)
typedef struct {
blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */
blkif_vdev_t device; /* 8: Device number (opaque 16 bit value). */
u16 info; /* 10: Device type and flags (VDISK_*). */
} PACKED vdisk_t; /* 12 bytes */
#endif /* __SHARED_BLKIF_H__ */
@@ -0,0 +1,120 @@
/******************************************************************************
* ctrl_if.h
*
* Management functions for special interface to the domain controller.
*
* Copyright (c) 2004, K A Fraser
*/
#ifndef __ASM_XEN__CTRL_IF_H__
#define __ASM_XEN__CTRL_IF_H__
#include <asm/hypervisor.h>
typedef control_msg_t ctrl_msg_t;
/*
* Callback function type. Called for asynchronous processing of received
* request messages, and responses to previously-transmitted request messages.
* The parameters are (@msg, @id).
* @msg: Original request/response message (not a copy). The message can be
* modified in-place by the handler (e.g., a response callback can
* turn a request message into a response message in place). The message
* is no longer accessible after the callback handler returns -- if the
* message is required to persist for longer then it must be copied.
* @id: (Response callbacks only) The 'id' that was specified when the
* original request message was queued for transmission.
*/
typedef void (*ctrl_msg_handler_t)(ctrl_msg_t *, unsigned long);
/*
* Send @msg to the domain controller. Execute @hnd when a response is
* received, passing the response message and the specified @id. This
* operation will not block: it will return -EAGAIN if there is no space.
* Notes:
* 1. The @msg is copied if it is transmitted and so can be freed after this
* function returns.
* 2. If @hnd is NULL then no callback is executed.
*/
int ctrl_if_send_message_noblock(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id);
/*
* Send @msg to the domain controller. Execute @hnd when a response is
* received, passing the response message and the specified @id. This
* operation will block until the message is sent, or a signal is received
* for the calling process (unless @wait_state is TASK_UNINTERRUPTIBLE).
* Notes:
* 1. The @msg is copied if it is transmitted and so can be freed after this
* function returns.
* 2. If @hnd is NULL then no callback is executed.
*/
int ctrl_if_send_message_block(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id,
long wait_state);
/*
* Request a callback when there is /possibly/ space to immediately send a
* message to the domain controller. This function returns 0 if there is
* already space to trasnmit a message --- in this case the callback task /may/
* still be executed. If this function returns 1 then the callback /will/ be
* executed when space becomes available.
*/
int ctrl_if_enqueue_space_callback(struct work_struct *task);
/*
* Send a response (@msg) to a message from the domain controller. This will
* never block.
* Notes:
* 1. The @msg is copied and so can be freed after this function returns.
* 2. The @msg may be the original request message, modified in-place.
*/
void ctrl_if_send_response(ctrl_msg_t *msg);
/*
* Register a receiver for typed messages from the domain controller. The
* handler (@hnd) is called for every received message of specified @type.
* Returns TRUE (non-zero) if the handler was successfully registered.
* If CALLBACK_IN_BLOCKING CONTEXT is specified in @flags then callbacks will
* occur in a context in which it is safe to yield (i.e., process context).
*/
#define CALLBACK_IN_BLOCKING_CONTEXT 1
int ctrl_if_register_receiver(
u8 type,
ctrl_msg_handler_t hnd,
unsigned int flags);
/*
* Unregister a receiver for typed messages from the domain controller. The
* handler (@hnd) will not be executed after this function returns.
*/
void ctrl_if_unregister_receiver(u8 type, ctrl_msg_handler_t hnd);
/* Suspend/resume notifications. */
void ctrl_if_suspend(void);
void ctrl_if_resume(void);
/* Start-of-day setup. */
void ctrl_if_init(void);
/*
* Returns TRUE if there are no outstanding message requests at the domain
* controller. This can be used to ensure that messages have really flushed
* through when it is not possible to use the response-callback interface.
* WARNING: If other subsystems are using the control interface then this
* function might never return TRUE!
*/
int ctrl_if_transmitter_empty(void); /* !! DANGEROUS FUNCTION !! */
/*
* Manually discard response messages from the domain controller.
* WARNING: This is usually done automatically -- this function should only
* be called when normal interrupt mechanisms are disabled!
*/
void ctrl_if_discard_responses(void); /* !! DANGEROUS FUNCTION !! */
#endif /* __ASM_XEN__CONTROL_IF_H__ */
@@ -0,0 +1,532 @@
/******************************************************************************
* domain_controller.h
*
* Interface to server controller (e.g., 'xend'). This header file defines the
* interface that is shared with guest OSes.
*
* Copyright (c) 2004, K A Fraser
*/
#ifndef __DOMAIN_CONTROLLER_H__
#define __DOMAIN_CONTROLLER_H__
#ifndef BASIC_START_INFO
#error "Xen header file hypervisor-if.h must already be included here."
#endif
/*
* EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS.
*/
typedef struct {
BASIC_START_INFO;
u16 domain_controller_evtchn; /* 320 */
} PACKED extended_start_info_t; /* 322 bytes */
#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */
#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
/*
* Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be
* interpreted by control software to determine the appropriate action. These
* are only really advisories: the controller can actually do as it likes.
*/
#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
/*
* CONTROLLER MESSAGING INTERFACE.
*/
typedef struct {
u8 type; /* 0: echoed in response */
u8 subtype; /* 1: echoed in response */
u8 id; /* 2: echoed in response */
u8 length; /* 3: number of bytes in 'msg' */
u8 msg[60]; /* 4: type-specific message data */
} PACKED control_msg_t; /* 64 bytes */
#define CONTROL_RING_SIZE 8
typedef u32 CONTROL_RING_IDX;
#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
typedef struct {
control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */
control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */
CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */
CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */
} PACKED control_if_t; /* 1040 bytes */
/*
* Top-level command types.
*/
#define CMSG_CONSOLE 0 /* Console */
#define CMSG_BLKIF_BE 1 /* Block-device backend */
#define CMSG_BLKIF_FE 2 /* Block-device frontend */
#define CMSG_NETIF_BE 3 /* Network-device backend */
#define CMSG_NETIF_FE 4 /* Network-device frontend */
#define CMSG_SHUTDOWN 6 /* Shutdown messages */
/******************************************************************************
* CONSOLE DEFINITIONS
*/
/*
* Subtypes for console messages.
*/
#define CMSG_CONSOLE_DATA 0
/******************************************************************************
* BLOCK-INTERFACE FRONTEND DEFINITIONS
*/
/* Messages from domain controller to guest. */
#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0
/* Messages from guest to domain controller. */
#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33
#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34
/* These are used by both front-end and back-end drivers. */
#define blkif_vdev_t u16
#define blkif_pdev_t u16
#define blkif_sector_t u64
/*
* CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED:
* Notify a guest about a status change on one of its block interfaces.
* If the interface is DESTROYED or DOWN then the interface is disconnected:
* 1. The shared-memory frame is available for reuse.
* 2. Any unacknowledged messgaes pending on the interface were dropped.
*/
#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
typedef struct {
u32 handle; /* 0 */
u32 status; /* 4 */
u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */
/*
* CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
* status-change notifications. When the driver comes UP then the controller
* will send a notification for each interface that currently exists.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
*/
#define BLKIF_DRIVER_STATUS_DOWN 0
#define BLKIF_DRIVER_STATUS_UP 1
typedef struct {
/* IN */
u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
/* OUT */
/*
* Tells driver how many interfaces it should expect to immediately
* receive notifications about.
*/
u32 nr_interfaces; /* 4 */
} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */
/*
* CMSG_BLKIF_FE_INTERFACE_CONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_CONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
u32 __pad;
memory_t shmem_frame; /* 8 */
MEMORY_PADDING;
} PACKED blkif_fe_interface_connect_t; /* 16 bytes */
/*
* CMSG_BLKIF_FE_INTERFACE_DISCONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_DISCONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */
/******************************************************************************
* BLOCK-INTERFACE BACKEND DEFINITIONS
*/
/* Messages from domain controller. */
#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */
#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */
#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */
#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */
#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */
#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */
/* Messages to domain controller. */
#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32
/*
* Message request/response definitions for block-device messages.
*/
typedef struct {
blkif_sector_t sector_start; /* 0 */
blkif_sector_t sector_length; /* 8 */
blkif_pdev_t device; /* 16 */
u16 __pad; /* 18 */
} PACKED blkif_extent_t; /* 20 bytes */
/* Non-specific 'okay' return. */
#define BLKIF_BE_STATUS_OKAY 0
/* Non-specific 'error' return. */
#define BLKIF_BE_STATUS_ERROR 1
/* The following are specific error returns. */
#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2
#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3
#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4
#define BLKIF_BE_STATUS_VBD_EXISTS 5
#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6
#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7
#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8
#define BLKIF_BE_STATUS_MAPPING_ERROR 9
/* This macro can be used to create an array of descriptive error strings. */
#define BLKIF_BE_STATUS_ERRORS { \
"Okay", \
"Non-specific error", \
"Interface already exists", \
"Interface not found", \
"Interface is still connected", \
"VBD already exists", \
"VBD not found", \
"Out of memory", \
"Extent not found for VBD", \
"Could not map domain memory" }
/*
* CMSG_BLKIF_BE_CREATE:
* When the driver sends a successful response then the interface is fully
* created. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_create_t; /* 12 bytes */
/*
* CMSG_BLKIF_BE_DESTROY:
* When the driver sends a successful response then the interface is fully
* torn down. The controller will send a DESTROYED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Identify interface to be destroyed. */
u32 blkif_handle; /* 4: ...ditto... */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_destroy_t; /* 12 bytes */
/*
* CMSG_BLKIF_BE_CONNECT:
* When the driver sends a successful response then the interface is fully
* connected. The controller will send a CONNECTED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
memory_t shmem_frame; /* 8: Page cont. shared comms window. */
MEMORY_PADDING;
u32 evtchn; /* 16: Event channel for notifications. */
/* OUT */
u32 status; /* 20 */
} PACKED blkif_be_connect_t; /* 24 bytes */
/*
* CMSG_BLKIF_BE_DISCONNECT:
* When the driver sends a successful response then the interface is fully
* disconnected. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_disconnect_t; /* 12 bytes */
/* CMSG_BLKIF_BE_VBD_CREATE */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */
u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_create_t; /* 16 bytes */
/* CMSG_BLKIF_BE_VBD_DESTROY */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
u16 __pad; /* 10 */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */
/* CMSG_BLKIF_BE_VBD_GROW */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_extent_t extent; /* 8: Physical extent to append to VBD. */
blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */
u16 __pad; /* 30 */
/* OUT */
u32 status; /* 32 */
} PACKED blkif_be_vbd_grow_t; /* 36 bytes */
/* CMSG_BLKIF_BE_VBD_SHRINK */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
u16 __pad; /* 10 */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */
/*
* CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the back-end driver is DOWN or UP.
* If the driver goes DOWN while interfaces are still UP, the controller
* will automatically send DOWN notifications.
*/
typedef struct {
u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */
/******************************************************************************
* NETWORK-INTERFACE FRONTEND DEFINITIONS
*/
/* Messages from domain controller to guest. */
#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0
/* Messages from guest to domain controller. */
#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
/*
* CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
* Notify a guest about a status change on one of its network interfaces.
* If the interface is DESTROYED or DOWN then the interface is disconnected:
* 1. The shared-memory frame is available for reuse.
* 2. Any unacknowledged messgaes pending on the interface were dropped.
*/
#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
typedef struct {
u32 handle; /* 0 */
u32 status; /* 4 */
u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */
u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */
} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */
/*
* CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
* status-change notifications. When the driver comes UP then the controller
* will send a notification for each interface that currently exists.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
*/
#define NETIF_DRIVER_STATUS_DOWN 0
#define NETIF_DRIVER_STATUS_UP 1
typedef struct {
/* IN */
u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
/* OUT */
/*
* Tells driver how many interfaces it should expect to immediately
* receive notifications about.
*/
u32 nr_interfaces; /* 4 */
} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */
/*
* CMSG_NETIF_FE_INTERFACE_CONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_CONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
u32 __pad; /* 4 */
memory_t tx_shmem_frame; /* 8 */
MEMORY_PADDING;
memory_t rx_shmem_frame; /* 16 */
MEMORY_PADDING;
} PACKED netif_fe_interface_connect_t; /* 24 bytes */
/*
* CMSG_NETIF_FE_INTERFACE_DISCONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_DISCONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */
/******************************************************************************
* NETWORK-INTERFACE BACKEND DEFINITIONS
*/
/* Messages from domain controller. */
#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */
#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */
#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
/* Messages to domain controller. */
#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32
/*
* Message request/response definitions for net-device messages.
*/
/* Non-specific 'okay' return. */
#define NETIF_BE_STATUS_OKAY 0
/* Non-specific 'error' return. */
#define NETIF_BE_STATUS_ERROR 1
/* The following are specific error returns. */
#define NETIF_BE_STATUS_INTERFACE_EXISTS 2
#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3
#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4
#define NETIF_BE_STATUS_OUT_OF_MEMORY 5
#define NETIF_BE_STATUS_MAPPING_ERROR 6
/* This macro can be used to create an array of descriptive error strings. */
#define NETIF_BE_STATUS_ERRORS { \
"Okay", \
"Non-specific error", \
"Interface already exists", \
"Interface not found", \
"Interface is still connected", \
"Out of memory", \
"Could not map domain memory" }
/*
* CMSG_NETIF_BE_CREATE:
* When the driver sends a successful response then the interface is fully
* created. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
u8 mac[6]; /* 8 */
u16 __pad; /* 14 */
/* OUT */
u32 status; /* 16 */
} PACKED netif_be_create_t; /* 20 bytes */
/*
* CMSG_NETIF_BE_DESTROY:
* When the driver sends a successful response then the interface is fully
* torn down. The controller will send a DESTROYED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Identify interface to be destroyed. */
u32 netif_handle; /* 4: ...ditto... */
/* OUT */
u32 status; /* 8 */
} PACKED netif_be_destroy_t; /* 12 bytes */
/*
* CMSG_NETIF_BE_CONNECT:
* When the driver sends a successful response then the interface is fully
* connected. The controller will send a CONNECTED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */
MEMORY_PADDING;
memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */
MEMORY_PADDING;
u16 evtchn; /* 24: Event channel for notifications. */
u16 __pad; /* 26 */
/* OUT */
u32 status; /* 28 */
} PACKED netif_be_connect_t; /* 32 bytes */
/*
* CMSG_NETIF_BE_DISCONNECT:
* When the driver sends a successful response then the interface is fully
* disconnected. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED netif_be_disconnect_t; /* 12 bytes */
/*
* CMSG_NETIF_BE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the back-end driver is DOWN or UP.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically send DOWN notifications.
*/
typedef struct {
u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
} PACKED netif_be_driver_status_changed_t; /* 4 bytes */
/******************************************************************************
* SHUTDOWN DEFINITIONS
*/
/*
* Subtypes for shutdown messages.
*/
#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */
#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */
#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */
/* SHUTDOWN_suspend. */
#endif /* __DOMAIN_CONTROLLER_H__ */
@@ -0,0 +1,83 @@
/******************************************************************************
* evtchn.h
*
* Communication via Xen event channels.
* Also definitions for the device that demuxes notifications to userspace.
*
* Copyright (c) 2004, K A Fraser
*/
#ifndef __ASM_EVTCHN_H__
#define __ASM_EVTCHN_H__
#include <linux/config.h>
#include <asm/hypervisor.h>
#include <asm/ptrace.h>
#include <asm/synch_bitops.h>
#include <asm/hypervisor-ifs/event_channel.h>
/*
* LOW-LEVEL DEFINITIONS
*/
/* Entry point for notifications into Linux subsystems. */
void evtchn_do_upcall(struct pt_regs *regs);
/* Entry point for notifications into the userland character device. */
void evtchn_device_upcall(int port);
static inline void mask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
synch_set_bit(port, &s->evtchn_mask[0]);
}
static inline void unmask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
synch_clear_bit(port, &s->evtchn_mask[0]);
/*
* The following is basically the equivalent of 'hw_resend_irq'. Just like
* a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
*/
if ( synch_test_bit (port, &s->evtchn_pending[0]) &&
!synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) )
{
s->vcpu_data[0].evtchn_upcall_pending = 1;
if ( !s->vcpu_data[0].evtchn_upcall_mask )
evtchn_do_upcall(NULL);
}
}
static inline void clear_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
synch_clear_bit(port, &s->evtchn_pending[0]);
}
static inline void notify_via_evtchn(int port)
{
evtchn_op_t op;
op.cmd = EVTCHNOP_send;
op.u.send.local_port = port;
(void)HYPERVISOR_event_channel_op(&op);
}
/*
* CHARACTER-DEVICE DEFINITIONS
*/
/* /dev/xen/evtchn resides at device number major=10, minor=200 */
#define EVTCHN_MINOR 200
/* /dev/xen/evtchn ioctls: */
/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
#define EVTCHN_RESET _IO('E', 1)
/* EVTCHN_BIND: Bind to teh specified event-channel port. */
#define EVTCHN_BIND _IO('E', 2)
/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
#define EVTCHN_UNBIND _IO('E', 3)
#endif /* __ASM_EVTCHN_H__ */
@@ -0,0 +1,138 @@
/******************************************************************************
* arch-i386/hypervisor-if.h
*
* Guest OS interface to x86 32-bit Xen.
*/
#ifndef __HYPERVISOR_IF_I386_H__
#define __HYPERVISOR_IF_I386_H__
/*
* Pointers and other address fields inside interface structures are padded to
* 64 bits. This means that field alignments aren't different between 32- and
* 64-bit architectures.
*/
/* NB. Multi-level macro ensures __LINE__ is expanded before concatenation. */
#define __MEMORY_PADDING(_X) u32 __pad_ ## _X
#define _MEMORY_PADDING(_X) __MEMORY_PADDING(_X)
#define MEMORY_PADDING _MEMORY_PADDING(__LINE__)
/*
* SEGMENT DESCRIPTOR TABLES
*/
/*
* A number of GDT entries are reserved by Xen. These are not situated at the
* start of the GDT because some stupid OSes export hard-coded selector values
* in their ABI. These hard-coded values are always near the start of the GDT,
* so Xen places itself out of the way.
*
* NB. The reserved range is inclusive (that is, both FIRST_RESERVED_GDT_ENTRY
* and LAST_RESERVED_GDT_ENTRY are reserved).
*/
#define NR_RESERVED_GDT_ENTRIES 40
#define FIRST_RESERVED_GDT_ENTRY 256
#define LAST_RESERVED_GDT_ENTRY \
(FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
/*
* These flat segments are in the Xen-private section of every GDT. Since these
* are also present in the initial GDT, many OSes will be able to avoid
* installing their own GDT.
*/
#define FLAT_RING1_CS 0x0819 /* GDT index 259 */
#define FLAT_RING1_DS 0x0821 /* GDT index 260 */
#define FLAT_RING3_CS 0x082b /* GDT index 261 */
#define FLAT_RING3_DS 0x0833 /* GDT index 262 */
#define FLAT_GUESTOS_CS FLAT_RING1_CS
#define FLAT_GUESTOS_DS FLAT_RING1_DS
#define FLAT_USER_CS FLAT_RING3_CS
#define FLAT_USER_DS FLAT_RING3_DS
/* And the trap vector is... */
#define TRAP_INSTR "int $0x82"
/*
* Virtual addresses beyond this are not modifiable by guest OSes. The
* machine->physical mapping table starts at this address, read-only.
*/
#define HYPERVISOR_VIRT_START (0xFC000000UL)
#ifndef machine_to_phys_mapping
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
#endif
#ifndef __ASSEMBLY__
/* NB. Both the following are 32 bits each. */
typedef unsigned long memory_t; /* Full-sized pointer/address/memory-size. */
typedef unsigned long cpureg_t; /* Full-sized register. */
/*
* Send an array of these to HYPERVISOR_set_trap_table()
*/
#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
#define TI_GET_IF(_ti) ((_ti)->flags & 4)
#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2))
typedef struct {
u8 vector; /* 0: exception vector */
u8 flags; /* 1: 0-3: privilege level; 4: clear event enable? */
u16 cs; /* 2: code selector */
memory_t address; /* 4: code address */
} PACKED trap_info_t; /* 8 bytes */
typedef struct
{
unsigned long ebx;
unsigned long ecx;
unsigned long edx;
unsigned long esi;
unsigned long edi;
unsigned long ebp;
unsigned long eax;
unsigned long ds;
unsigned long es;
unsigned long fs;
unsigned long gs;
unsigned long _unused;
unsigned long eip;
unsigned long cs;
unsigned long eflags;
unsigned long esp;
unsigned long ss;
} PACKED execution_context_t;
typedef struct {
u32 tsc_bits; /* 0: 32 bits read from the CPU's TSC. */
u32 tsc_bitshift; /* 4: 'tsc_bits' uses N:N+31 of TSC. */
} PACKED tsc_timestamp_t; /* 8 bytes */
/*
* The following is all CPU context. Note that the i387_ctxt block is filled
* in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
*/
typedef struct {
#define ECF_I387_VALID (1<<0)
unsigned long flags;
execution_context_t cpu_ctxt; /* User-level CPU registers */
char fpu_ctxt[256]; /* User-level FPU registers */
trap_info_t trap_ctxt[256]; /* Virtual IDT */
unsigned int fast_trap_idx; /* "Fast trap" vector offset */
unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
unsigned long guestos_ss, guestos_esp; /* Virtual TSS (only SS1/ESP1) */
unsigned long pt_base; /* CR3 (pagetable base) */
unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
unsigned long event_callback_cs; /* CS:EIP of event callback */
unsigned long event_callback_eip;
unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
unsigned long failsafe_callback_eip;
} PACKED full_execution_context_t;
#define ARCH_HAS_FAST_TRAP
#endif
#endif
@@ -0,0 +1,135 @@
/******************************************************************************
* arch-x86_64/hypervisor-if.h
*
* Guest OS interface to AMD x86-64 bit Xen.
*/
#ifndef __HYPERVISOR_IF_X86_64_H__
#define __HYPERVISOR_IF_X86_64_H__
/* Pointers are naturally 64 bits in this architecture; no padding needed. */
#define _MEMORY_PADDING(_X)
#define MEMORY_PADDING
/*
* SEGMENT DESCRIPTOR TABLES
*/
/*
* A number of GDT entries are reserved by Xen. These are not situated at the
* start of the GDT because some stupid OSes export hard-coded selector values
* in their ABI. These hard-coded values are always near the start of the GDT,
* so Xen places itself out of the way.
*
* NB. The reserved range is inclusive (that is, both FIRST_RESERVED_GDT_ENTRY
* and LAST_RESERVED_GDT_ENTRY are reserved).
*/
#define NR_RESERVED_GDT_ENTRIES 40
#define FIRST_RESERVED_GDT_ENTRY 256
#define LAST_RESERVED_GDT_ENTRY \
(FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
/*
* 64-bit segment selectors
* These flat segments are in the Xen-private section of every GDT. Since these
* are also present in the initial GDT, many OSes will be able to avoid
* installing their own GDT.
*/
#define FLAT_RING3_CS32 0x0823 /* GDT index 260 */
#define FLAT_RING3_CS64 0x082b /* GDT index 261 */
#define FLAT_RING3_DS 0x0833 /* GDT index 262 */
#define FLAT_GUESTOS_DS FLAT_RING3_DS
#define FLAT_GUESTOS_CS FLAT_RING3_CS64
#define FLAT_GUESTOS_CS32 FLAT_RING3_CS32
#define FLAT_USER_DS FLAT_RING3_DS
#define FLAT_USER_CS FLAT_RING3_CS64
#define FLAT_USER_CS32 FLAT_RING3_CS32
/* And the trap vector is... */
#define TRAP_INSTR "syscall"
/* The machine->physical mapping table starts at this address, read-only. */
#ifndef machine_to_phys_mapping
#define machine_to_phys_mapping ((unsigned long *)0xffff810000000000ULL)
#endif
#ifndef __ASSEMBLY__
/* NB. Both the following are 64 bits each. */
typedef unsigned long memory_t; /* Full-sized pointer/address/memory-size. */
typedef unsigned long cpureg_t; /* Full-sized register. */
/*
* Send an array of these to HYPERVISOR_set_trap_table()
*/
#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
#define TI_GET_IF(_ti) ((_ti)->flags & 4)
#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2))
typedef struct {
u8 vector; /* 0: exception vector */
u8 flags; /* 1: 0-3: privilege level; 4: clear event enable? */
u16 cs; /* 2: code selector */
u32 __pad; /* 4 */
memory_t address; /* 8: code address */
} PACKED trap_info_t; /* 16 bytes */
typedef struct
{
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long rbp;
unsigned long rbx;
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 rip;
unsigned long cs;
unsigned long eflags;
unsigned long rsp;
unsigned long ss;
} PACKED execution_context_t;
/*
* NB. This may become a 64-bit count with no shift. If this happens then the
* structure size will still be 8 bytes, so no other alignments will change.
*/
typedef struct {
u32 tsc_bits; /* 0: 32 bits read from the CPU's TSC. */
u32 tsc_bitshift; /* 4: 'tsc_bits' uses N:N+31 of TSC. */
} PACKED tsc_timestamp_t; /* 8 bytes */
/*
* The following is all CPU context. Note that the i387_ctxt block is filled
* in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
*/
typedef struct {
#define ECF_I387_VALID (1<<0)
unsigned long flags;
execution_context_t cpu_ctxt; /* User-level CPU registers */
char fpu_ctxt[512]; /* User-level FPU registers */
trap_info_t trap_ctxt[256]; /* Virtual IDT */
unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
unsigned long guestos_ss, guestos_esp; /* Virtual TSS (only SS1/ESP1) */
unsigned long pt_base; /* CR3 (pagetable base) */
unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
unsigned long event_callback_cs; /* CS:EIP of event callback */
unsigned long event_callback_eip;
unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
unsigned long failsafe_callback_eip;
} PACKED full_execution_context_t;
#endif /* !__ASSEMBLY__ */
#endif /* __HYPERVISOR_IF_H__ */
@@ -0,0 +1,356 @@
/******************************************************************************
* dom0_ops.h
*
* Process command requests from domain-0 guest OS.
*
* Copyright (c) 2002-2003, B Dragovic
* Copyright (c) 2002-2004, K Fraser
*/
#ifndef __DOM0_OPS_H__
#define __DOM0_OPS_H__
#include "hypervisor-if.h"
#include "sched_ctl.h"
/*
* Make sure you increment the interface version whenever you modify this file!
* This makes sure that old versions of dom0 tools will stop working in a
* well-defined way (rather than crashing the machine, for instance).
*/
#define DOM0_INTERFACE_VERSION 0xAAAA0010
#define MAX_DOMAIN_NAME 16
/************************************************************************/
#define DOM0_GETMEMLIST 2
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 __pad;
memory_t max_pfns; /* 8 */
MEMORY_PADDING;
void *buffer; /* 16 */
MEMORY_PADDING;
/* OUT variables. */
memory_t num_pfns; /* 24 */
MEMORY_PADDING;
} PACKED dom0_getmemlist_t; /* 32 bytes */
#define DOM0_SCHEDCTL 6
/* struct sched_ctl_cmd is from sched-ctl.h */
typedef struct sched_ctl_cmd dom0_schedctl_t;
#define DOM0_ADJUSTDOM 7
/* struct sched_adjdom_cmd is from sched-ctl.h */
typedef struct sched_adjdom_cmd dom0_adjustdom_t;
#define DOM0_CREATEDOMAIN 8
typedef struct {
/* IN parameters. */
memory_t memory_kb; /* 0 */
MEMORY_PADDING;
u8 name[MAX_DOMAIN_NAME]; /* 8 */
u32 cpu; /* 24 */
u32 __pad; /* 28 */
/* OUT parameters. */
domid_t domain; /* 32 */
} PACKED dom0_createdomain_t; /* 36 bytes */
#define DOM0_DESTROYDOMAIN 9
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
} PACKED dom0_destroydomain_t; /* 4 bytes */
#define DOM0_PAUSEDOMAIN 10
typedef struct {
/* IN parameters. */
domid_t domain; /* 0 */
} PACKED dom0_pausedomain_t; /* 4 bytes */
#define DOM0_UNPAUSEDOMAIN 11
typedef struct {
/* IN parameters. */
domid_t domain; /* 0 */
} PACKED dom0_unpausedomain_t; /* 4 bytes */
#define DOM0_GETDOMAININFO 12
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */ /* NB. IN/OUT variable. */
/* OUT variables. */
#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
#define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */
#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut itself down. */
#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
#define DOMFLAGS_CPUSHIFT 8
#define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code. */
#define DOMFLAGS_SHUTDOWNSHIFT 16
u32 flags; /* 4 */
u8 name[MAX_DOMAIN_NAME]; /* 8 */
full_execution_context_t *ctxt; /* 24 */ /* NB. IN/OUT variable. */
MEMORY_PADDING;
memory_t tot_pages; /* 32 */
MEMORY_PADDING;
memory_t max_pages; /* 40 */
MEMORY_PADDING;
memory_t shared_info_frame; /* 48: MFN of shared_info struct */
MEMORY_PADDING;
u64 cpu_time; /* 56 */
} PACKED dom0_getdomaininfo_t; /* 64 bytes */
#define DOM0_BUILDDOMAIN 13
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 __pad; /* 4 */
/* IN/OUT parameters */
full_execution_context_t *ctxt; /* 8 */
MEMORY_PADDING;
} PACKED dom0_builddomain_t; /* 16 bytes */
#define DOM0_IOPL 14
typedef struct {
domid_t domain; /* 0 */
u32 iopl; /* 4 */
} PACKED dom0_iopl_t; /* 8 bytes */
#define DOM0_MSR 15
typedef struct {
/* IN variables. */
u32 write; /* 0 */
u32 cpu_mask; /* 4 */
u32 msr; /* 8 */
u32 in1; /* 12 */
u32 in2; /* 16 */
/* OUT variables. */
u32 out1; /* 20 */
u32 out2; /* 24 */
} PACKED dom0_msr_t; /* 28 bytes */
#define DOM0_DEBUG 16
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u8 opcode; /* 4 */
u8 __pad0, __pad1, __pad2;
u32 in1; /* 8 */
u32 in2; /* 12 */
u32 in3; /* 16 */
u32 in4; /* 20 */
/* OUT variables. */
u32 status; /* 24 */
u32 out1; /* 28 */
u32 out2; /* 32 */
} PACKED dom0_debug_t; /* 36 bytes */
/*
* Set clock such that it would read <secs,usecs> after 00:00:00 UTC,
* 1 January, 1970 if the current system time was <system_time>.
*/
#define DOM0_SETTIME 17
typedef struct {
/* IN variables. */
u32 secs; /* 0 */
u32 usecs; /* 4 */
u64 system_time; /* 8 */
} PACKED dom0_settime_t; /* 16 bytes */
#define DOM0_GETPAGEFRAMEINFO 18
#define NOTAB 0 /* normal page */
#define L1TAB (1<<28)
#define L2TAB (2<<28)
#define L3TAB (3<<28)
#define L4TAB (4<<28)
#define XTAB (0xf<<28) /* invalid page */
#define LTAB_MASK XTAB
typedef struct {
/* IN variables. */
memory_t pfn; /* 0: Machine page frame number to query. */
MEMORY_PADDING;
domid_t domain; /* 8: To which domain does the frame belong? */
/* OUT variables. */
/* Is the page PINNED to a type? */
u32 type; /* 12: see above type defs */
} PACKED dom0_getpageframeinfo_t; /* 16 bytes */
/*
* Read console content from Xen buffer ring.
*/
#define DOM0_READCONSOLE 19
typedef struct {
memory_t str; /* 0 */
MEMORY_PADDING;
u32 count; /* 8 */
u32 cmd; /* 12 */
} PACKED dom0_readconsole_t; /* 16 bytes */
/*
* Pin Domain to a particular CPU (use -1 to unpin)
*/
#define DOM0_PINCPUDOMAIN 20
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
s32 cpu; /* 4: -1 implies unpin */
} PACKED dom0_pincpudomain_t; /* 8 bytes */
/* Get trace buffers physical base pointer */
#define DOM0_GETTBUFS 21
typedef struct {
/* OUT variables */
memory_t phys_addr; /* 0: location of the trace buffers */
MEMORY_PADDING;
u32 size; /* 8: size of each trace buffer, in bytes */
} PACKED dom0_gettbufs_t; /* 12 bytes */
/*
* Get physical information about the host machine
*/
#define DOM0_PHYSINFO 22
typedef struct {
u32 ht_per_core; /* 0 */
u32 cores; /* 4 */
u32 cpu_khz; /* 8 */
u32 __pad; /* 12 */
memory_t total_pages; /* 16 */
MEMORY_PADDING;
memory_t free_pages; /* 24 */
MEMORY_PADDING;
} PACKED dom0_physinfo_t; /* 32 bytes */
/*
* Allow a domain access to a physical PCI device
*/
#define DOM0_PCIDEV_ACCESS 23
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 bus; /* 4 */
u32 dev; /* 8 */
u32 func; /* 12 */
u32 enable; /* 16 */
} PACKED dom0_pcidev_access_t; /* 20 bytes */
/*
* Get the ID of the current scheduler.
*/
#define DOM0_SCHED_ID 24
typedef struct {
/* OUT variable */
u32 sched_id; /* 0 */
} PACKED dom0_sched_id_t; /* 4 bytes */
/*
* Control shadow pagetables operation
*/
#define DOM0_SHADOW_CONTROL 25
#define DOM0_SHADOW_CONTROL_OP_OFF 0
#define DOM0_SHADOW_CONTROL_OP_ENABLE_TEST 1
#define DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY 2
#define DOM0_SHADOW_CONTROL_OP_ENABLE_TRANSLATE 3
#define DOM0_SHADOW_CONTROL_OP_FLUSH 10 /* table ops */
#define DOM0_SHADOW_CONTROL_OP_CLEAN 11
#define DOM0_SHADOW_CONTROL_OP_PEEK 12
#define DOM0_SHADOW_CONTROL_OP_CLEAN2 13
typedef struct dom0_shadow_control
{
u32 fault_count;
u32 dirty_count;
u32 dirty_net_count;
u32 dirty_block_count;
} dom0_shadow_control_stats_t;
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 op; /* 4 */
unsigned long *dirty_bitmap; /* 8: pointer to locked buffer */
MEMORY_PADDING;
/* IN/OUT variables. */
memory_t pages; /* 16: size of buffer, updated with actual size */
MEMORY_PADDING;
/* OUT variables. */
dom0_shadow_control_stats_t stats;
} PACKED dom0_shadow_control_t;
#define DOM0_SETDOMAINNAME 26
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u8 name[MAX_DOMAIN_NAME]; /* 4 */
} PACKED dom0_setdomainname_t; /* 20 bytes */
#define DOM0_SETDOMAININITIALMEM 27
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 __pad;
memory_t initial_memkb; /* 8 */
MEMORY_PADDING;
} PACKED dom0_setdomaininitialmem_t; /* 16 bytes */
#define DOM0_SETDOMAINMAXMEM 28
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 __pad;
memory_t max_memkb; /* 8 */
MEMORY_PADDING;
} PACKED dom0_setdomainmaxmem_t; /* 16 bytes */
#define DOM0_GETPAGEFRAMEINFO2 29 /* batched interface */
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
u32 __pad;
memory_t num; /* 8 */
MEMORY_PADDING;
/* IN/OUT variables. */
unsigned long *array; /* 16 */
MEMORY_PADDING;
} PACKED dom0_getpageframeinfo2_t; /* 24 bytes */
typedef struct {
u32 cmd; /* 0 */
u32 interface_version; /* 4 */ /* DOM0_INTERFACE_VERSION */
union { /* 8 */
u32 dummy[18]; /* 72 bytes */
dom0_createdomain_t createdomain;
dom0_pausedomain_t pausedomain;
dom0_unpausedomain_t unpausedomain;
dom0_destroydomain_t destroydomain;
dom0_getmemlist_t getmemlist;
dom0_schedctl_t schedctl;
dom0_adjustdom_t adjustdom;
dom0_builddomain_t builddomain;
dom0_getdomaininfo_t getdomaininfo;
dom0_getpageframeinfo_t getpageframeinfo;
dom0_iopl_t iopl;
dom0_msr_t msr;
dom0_debug_t debug;
dom0_settime_t settime;
dom0_readconsole_t readconsole;
dom0_pincpudomain_t pincpudomain;
dom0_gettbufs_t gettbufs;
dom0_physinfo_t physinfo;
dom0_pcidev_access_t pcidev_access;
dom0_sched_id_t sched_id;
dom0_shadow_control_t shadow_control;
dom0_setdomainname_t setdomainname;
dom0_setdomaininitialmem_t setdomaininitialmem;
dom0_setdomainmaxmem_t setdomainmaxmem;
dom0_getpageframeinfo2_t getpageframeinfo2;
} PACKED u;
} PACKED dom0_op_t; /* 80 bytes */
#endif /* __DOM0_OPS_H__ */
@@ -0,0 +1,127 @@
/******************************************************************************
* event_channel.h
*
* Event channels between domains.
*
* Copyright (c) 2003-2004, K A Fraser.
*/
#ifndef __HYPERVISOR_IFS__EVENT_CHANNEL_H__
#define __HYPERVISOR_IFS__EVENT_CHANNEL_H__
/*
* EVTCHNOP_bind_interdomain: Open an event channel between <dom1> and <dom2>.
* NOTES:
* 1. <dom1> and/or <dom2> may be specified as DOMID_SELF.
* 2. Only a sufficiently-privileged domain may create an event channel.
* 3. <port1> and <port2> are only supplied if the op succeeds.
*/
#define EVTCHNOP_bind_interdomain 0
typedef struct {
/* IN parameters. */
domid_t dom1, dom2; /* 0, 4 */
/* OUT parameters. */
u32 port1, port2; /* 8, 12 */
} PACKED evtchn_bind_interdomain_t; /* 16 bytes */
/*
* EVTCHNOP_bind_virq: Bind a local event channel to IRQ <irq>.
* NOTES:
* 1. A virtual IRQ may be bound to at most one event channel per domain.
*/
#define EVTCHNOP_bind_virq 1
typedef struct {
/* IN parameters. */
u32 virq; /* 0 */
/* OUT parameters. */
u32 port; /* 4 */
} PACKED evtchn_bind_virq_t; /* 8 bytes */
/*
* EVTCHNOP_bind_pirq: Bind a local event channel to IRQ <irq>.
* NOTES:
* 1. A physical IRQ may be bound to at most one event channel per domain.
* 2. Only a sufficiently-privileged domain may bind to a physical IRQ.
*/
#define EVTCHNOP_bind_pirq 2
typedef struct {
/* IN parameters. */
u32 pirq; /* 0 */
#define BIND_PIRQ__WILL_SHARE 1
u32 flags; /* BIND_PIRQ__* */ /* 4 */
/* OUT parameters. */
u32 port; /* 8 */
} PACKED evtchn_bind_pirq_t; /* 12 bytes */
/*
* EVTCHNOP_close: Close the communication channel which has an endpoint at
* <dom, port>.
* NOTES:
* 1. <dom> may be specified as DOMID_SELF.
* 2. Only a sufficiently-privileged domain may close an event channel
* for which <dom> is not DOMID_SELF.
*/
#define EVTCHNOP_close 3
typedef struct {
/* IN parameters. */
domid_t dom; /* 0 */
u32 port; /* 4 */
/* No OUT parameters. */
} PACKED evtchn_close_t; /* 8 bytes */
/*
* EVTCHNOP_send: Send an event to the remote end of the channel whose local
* endpoint is <DOMID_SELF, local_port>.
*/
#define EVTCHNOP_send 4
typedef struct {
/* IN parameters. */
u32 local_port; /* 0 */
/* No OUT parameters. */
} PACKED evtchn_send_t; /* 4 bytes */
/*
* EVTCHNOP_status: Get the current status of the communication channel which
* has an endpoint at <dom, port>.
* NOTES:
* 1. <dom> may be specified as DOMID_SELF.
* 2. Only a sufficiently-privileged domain may obtain the status of an event
* channel for which <dom> is not DOMID_SELF.
*/
#define EVTCHNOP_status 5
typedef struct {
/* IN parameters */
domid_t dom; /* 0 */
u32 port; /* 4 */
/* OUT parameters */
#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */
#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
u32 status; /* 8 */
union { /* 12 */
struct {
domid_t dom; /* 12 */
u32 port; /* 16 */
} PACKED interdomain; /* EVTCHNSTAT_interdomain */
u32 pirq; /* EVTCHNSTAT_pirq */ /* 12 */
u32 virq; /* EVTCHNSTAT_virq */ /* 12 */
} PACKED u;
} PACKED evtchn_status_t; /* 20 bytes */
typedef struct {
u32 cmd; /* EVTCHNOP_* */ /* 0 */
u32 __reserved; /* 4 */
union { /* 8 */
evtchn_bind_interdomain_t bind_interdomain;
evtchn_bind_virq_t bind_virq;
evtchn_bind_pirq_t bind_pirq;
evtchn_close_t close;
evtchn_send_t send;
evtchn_status_t status;
u8 __dummy[24];
} PACKED u;
} PACKED evtchn_op_t; /* 32 bytes */
#endif /* __HYPERVISOR_IFS__EVENT_CHANNEL_H__ */
@@ -0,0 +1,395 @@
/******************************************************************************
* hypervisor-if.h
*
* Guest OS interface to Xen.
*/
#ifndef __HYPERVISOR_IF_H__
#define __HYPERVISOR_IF_H__
/* GCC-specific way to pack structure definitions (no implicit padding). */
#define PACKED __attribute__ ((packed))
#if defined(__i386__)
#include "arch-x86_32.h"
#elif defined(__x86_64__)
#include "arch-x86_64.h"
#else
#error "Unsupported architecture"
#endif
/*
* HYPERVISOR "SYSTEM CALLS"
*/
/* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */
#define __HYPERVISOR_set_trap_table 0
#define __HYPERVISOR_mmu_update 1
#define __HYPERVISOR_set_gdt 2
#define __HYPERVISOR_stack_switch 3
#define __HYPERVISOR_set_callbacks 4
#define __HYPERVISOR_fpu_taskswitch 5
#define __HYPERVISOR_sched_op 6
#define __HYPERVISOR_dom0_op 7
#define __HYPERVISOR_set_debugreg 8
#define __HYPERVISOR_get_debugreg 9
#define __HYPERVISOR_update_descriptor 10
#define __HYPERVISOR_set_fast_trap 11
#define __HYPERVISOR_dom_mem_op 12
#define __HYPERVISOR_multicall 13
#define __HYPERVISOR_update_va_mapping 14
#define __HYPERVISOR_set_timer_op 15
#define __HYPERVISOR_event_channel_op 16
#define __HYPERVISOR_xen_version 17
#define __HYPERVISOR_console_io 18
#define __HYPERVISOR_physdev_op 19
#define __HYPERVISOR_update_va_mapping_otherdomain 20
/*
* MULTICALLS
*
* Multicalls are listed in an array, with each element being a fixed size
* (BYTES_PER_MULTICALL_ENTRY). Each is of the form (op, arg1, ..., argN)
* where each element of the tuple is a machine word.
*/
#define ARGS_PER_MULTICALL_ENTRY 8
/*
* VIRTUAL INTERRUPTS
*
* Virtual interrupts that a guest OS may receive from the hypervisor.
*/
#define VIRQ_MISDIRECT 0 /* Catch-all interrupt for unbound VIRQs. */
#define VIRQ_TIMER 1 /* Timebase update, and/or requested timeout. */
#define VIRQ_DEBUG 2 /* Request guest to dump debug info. */
#define VIRQ_CONSOLE 3 /* (DOM0) bytes received on emergency console. */
#define VIRQ_DOM_EXC 4 /* (DOM0) Exceptional event for some domain. */
#define NR_VIRQS 5
/*
* MMU-UPDATE REQUESTS
*
* HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
* ptr[1:0] specifies the appropriate MMU_* command.
*
* GPS (General-Purpose Subject)
* -----------------------------
* This domain that must own all non-page-table pages that are involved in
* MMU updates. By default it is the domain that executes mmu_update(). If the
* caller has sufficient privilege then it can be changed by executing
* MMUEXT_SET_SUBJECTDOM.
*
* PTS (Page-Table Subject)
* ------------------------
* This domain must own all the page-table pages that are subject to MMU
* updates. By default it is the domain that executes mmu_update(). If the
* caller has sufficient privilege then it can be changed by executing
* MMUEXT_SET_SUBJECTDOM with val[14] (SET_PAGETABLE_SUBJECTDOM) set.
*
* ptr[1:0] == MMU_NORMAL_PT_UPDATE:
* Updates an entry in a page table.
* ptr[:2] -- machine address of the page-table entry to modify [1]
* val -- value to write [2]
*
* ptr[1:0] == MMU_MACHPHYS_UPDATE:
* Updates an entry in the machine->pseudo-physical mapping table.
* ptr[:2] -- machine address within the frame whose mapping to modify [3]
* val -- value to write into the mapping entry
*
* ptr[1:0] == MMU_EXTENDED_COMMAND:
* val[7:0] -- MMUEXT_* command
*
* val[7:0] == MMUEXT_(UN)PIN_*_TABLE:
* ptr[:2] -- machine address of frame to be (un)pinned as a p.t. page [1]
*
* val[7:0] == MMUEXT_NEW_BASEPTR:
* ptr[:2] -- machine address of new page-table base to install in MMU [1]
*
* val[7:0] == MMUEXT_TLB_FLUSH:
* no additional arguments
*
* val[7:0] == MMUEXT_INVLPG:
* ptr[:2] -- linear address to be flushed from the TLB
*
* val[7:0] == MMUEXT_SET_LDT:
* ptr[:2] -- linear address of LDT base (NB. must be page-aligned)
* val[:8] -- number of entries in LDT
*
* val[7:0] == MMUEXT_SET_SUBJECTDOM:
* val[14] -- if TRUE then sets the PTS in addition to the GPS.
* (ptr[31:15],val[31:15]) -- dom[31:0]
*
* val[7:0] == MMUEXT_REASSIGN_PAGE:
* ptr[:2] -- machine address within page to be reassigned to the GPS.
*
* val[7:0] == MMUEXT_RESET_SUBJECTDOM:
* Resets both the GPS and the PTS to their defaults (i.e., calling domain).
*
* Notes on constraints on the above arguments:
* [1] The page frame containing the machine address must belong to the PTS.
* [2] If the PTE is valid (i.e., bit 0 is set) then the specified page frame
* must belong to:
* (a) the PTS (if the PTE is part of a non-L1 table); or
* (b) the GPS (if the PTE is part of an L1 table).
* [3] The page frame containing the machine address must belong to the GPS.
*/
#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
#define MMU_MACHPHYS_UPDATE 2 /* ptr = MA of frame to modify entry for */
#define MMU_EXTENDED_COMMAND 3 /* least 8 bits of val demux further */
#define MMUEXT_PIN_L1_TABLE 0 /* ptr = MA of frame to pin */
#define MMUEXT_PIN_L2_TABLE 1 /* ptr = MA of frame to pin */
#define MMUEXT_PIN_L3_TABLE 2 /* ptr = MA of frame to pin */
#define MMUEXT_PIN_L4_TABLE 3 /* ptr = MA of frame to pin */
#define MMUEXT_UNPIN_TABLE 4 /* ptr = MA of frame to unpin */
#define MMUEXT_NEW_BASEPTR 5 /* ptr = MA of new pagetable base */
#define MMUEXT_TLB_FLUSH 6 /* ptr = NULL */
#define MMUEXT_INVLPG 7 /* ptr = VA to invalidate */
#define MMUEXT_SET_LDT 8 /* ptr = VA of table; val = # entries */
#define MMUEXT_SET_SUBJECTDOM 9 /* (ptr[31:15],val[31:15]) = dom[31:0] */
#define SET_PAGETABLE_SUBJECTDOM (1<<14) /* OR into 'val' arg of SUBJECTDOM */
#define MMUEXT_REASSIGN_PAGE 10
#define MMUEXT_RESET_SUBJECTDOM 11
#define MMUEXT_CMD_MASK 255
#define MMUEXT_CMD_SHIFT 8
/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
#define UVMF_FLUSH_TLB 1 /* Flush entire TLB. */
#define UVMF_INVLPG 2 /* Flush the VA mapping being updated. */
/*
* Commands to HYPERVISOR_sched_op().
*/
#define SCHEDOP_yield 0 /* Give up the CPU voluntarily. */
#define SCHEDOP_block 1 /* Block until an event is received. */
#define SCHEDOP_shutdown 2 /* Stop executing this domain. */
#define SCHEDOP_cmdmask 255 /* 8-bit command. */
#define SCHEDOP_reasonshift 8 /* 8-bit reason code. (SCHEDOP_shutdown) */
/*
* Commands to HYPERVISOR_console_io().
*/
#define CONSOLEIO_write 0
#define CONSOLEIO_read 1
/*
* Commands to HYPERVISOR_dom_mem_op().
*/
#define MEMOP_increase_reservation 0
#define MEMOP_decrease_reservation 1
#ifndef __ASSEMBLY__
typedef u32 domid_t;
/* DOMID_SELF is used in certain contexts to refer to oneself. */
#define DOMID_SELF (0x7FFFFFFEU)
/*
* Send an array of these to HYPERVISOR_mmu_update().
* NB. The fields are natural pointer/address size for this architecture.
*/
typedef struct
{
memory_t ptr; /* Machine address of PTE. */
memory_t val; /* New contents of PTE. */
} PACKED mmu_update_t;
/*
* Send an array of these to HYPERVISOR_multicall().
* NB. The fields are natural register size for this architecture.
*/
typedef struct
{
cpureg_t op;
cpureg_t args[7];
} PACKED multicall_entry_t;
/* Event channel endpoints per domain. */
#define NR_EVENT_CHANNELS 1024
/* No support for multi-processor guests. */
#define MAX_VIRT_CPUS 1
/*
* Xen/guestos shared data -- pointer provided in start_info.
* NB. We expect that this struct is smaller than a page.
*/
typedef struct shared_info_st
{
/*
* Per-VCPU information goes here. This will be cleaned up more when Xen
* actually supports multi-VCPU guests.
*/
struct {
/*
* 'evtchn_upcall_pending' is written non-zero by Xen to indicate
* a pending notification for a particular VCPU. It is then cleared
* by the guest OS /before/ checking for pending work, thus avoiding
* a set-and-check race. Note that the mask is only accessed by Xen
* on the CPU that is currently hosting the VCPU. This means that the
* pending and mask flags can be updated by the guest without special
* synchronisation (i.e., no need for the x86 LOCK prefix).
* This may seem suboptimal because if the pending flag is set by
* a different CPU then an IPI may be scheduled even when the mask
* is set. However, note:
* 1. The task of 'interrupt holdoff' is covered by the per-event-
* channel mask bits. A 'noisy' event that is continually being
* triggered can be masked at source at this very precise
* granularity.
* 2. The main purpose of the per-VCPU mask is therefore to restrict
* reentrant execution: whether for concurrency control, or to
* prevent unbounded stack usage. Whatever the purpose, we expect
* that the mask will be asserted only for short periods at a time,
* and so the likelihood of a 'spurious' IPI is suitably small.
* The mask is read before making an event upcall to the guest: a
* non-zero mask therefore guarantees that the VCPU will not receive
* an upcall activation. The mask is cleared when the VCPU requests
* to block: this avoids wakeup-waiting races.
*/
u8 evtchn_upcall_pending;
u8 evtchn_upcall_mask;
u8 pad0, pad1;
} PACKED vcpu_data[MAX_VIRT_CPUS]; /* 0 */
/*
* A domain can have up to 1024 "event channels" on which it can send
* and receive asynchronous event notifications. There are three classes
* of event that are delivered by this mechanism:
* 1. Bi-directional inter- and intra-domain connections. Domains must
* arrange out-of-band to set up a connection (usually the setup
* is initiated and organised by a privileged third party such as
* software running in domain 0).
* 2. Physical interrupts. A domain with suitable hardware-access
* privileges can bind an event-channel port to a physical interrupt
* source.
* 3. Virtual interrupts ('events'). A domain can bind an event-channel
* port to a virtual interrupt source, such as the virtual-timer
* device or the emergency console.
*
* Event channels are addressed by a "port index" between 0 and 1023.
* Each channel is associated with two bits of information:
* 1. PENDING -- notifies the domain that there is a pending notification
* to be processed. This bit is cleared by the guest.
* 2. MASK -- if this bit is clear then a 0->1 transition of PENDING
* will cause an asynchronous upcall to be scheduled. This bit is only
* updated by the guest. It is read-only within Xen. If a channel
* becomes pending while the channel is masked then the 'edge' is lost
* (i.e., when the channel is unmasked, the guest must manually handle
* pending notifications as no upcall will be scheduled by Xen).
*
* To expedite scanning of pending notifications, any 0->1 pending
* transition on an unmasked channel causes a corresponding bit in a
* 32-bit selector to be set. Each bit in the selector covers a 32-bit
* word in the PENDING bitfield array.
*/
u32 evtchn_pending[32]; /* 4 */
u32 evtchn_pending_sel; /* 132 */
u32 evtchn_mask[32]; /* 136 */
/*
* Time: The following abstractions are exposed: System Time, Clock Time,
* Domain Virtual Time. Domains can access Cycle counter time directly.
*/
u64 cpu_freq; /* 264: CPU frequency (Hz). */
/*
* The following values are updated periodically (and not necessarily
* atomically!). The guest OS detects this because 'time_version1' is
* incremented just before updating these values, and 'time_version2' is
* incremented immediately after. See the Xen-specific Linux code for an
* example of how to read these values safely (arch/xen/kernel/time.c).
*/
u32 time_version1; /* 272 */
u32 time_version2; /* 276 */
tsc_timestamp_t tsc_timestamp; /* TSC at last update of time vals. */
u64 system_time; /* Time, in nanosecs, since boot. */
u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
u32 wc_usec; /* Usecs 00:00:00 UTC, Jan 1, 1970. */
u64 domain_time; /* Domain virtual time, in nanosecs. */
/*
* Timeout values:
* Allow a domain to specify a timeout value in system time and
* domain virtual time.
*/
u64 wall_timeout; /* 312 */
u64 domain_timeout; /* 320 */
execution_context_t execution_context; /* 328 */
} PACKED shared_info_t;
/*
* Start-of-day memory layout for the initial domain (DOM0):
* 1. The domain is started within contiguous virtual-memory region.
* 2. The contiguous region begins and ends on an aligned 4MB boundary.
* 3. The region start corresponds to the load address of the OS image.
* If the load address is not 4MB aligned then the address is rounded down.
* 4. This the order of bootstrap elements in the initial virtual region:
* a. relocated kernel image
* b. initial ram disk [mod_start, mod_len]
* c. list of allocated page frames [mfn_list, nr_pages]
* d. bootstrap page tables [pt_base, CR3 (x86)]
* e. start_info_t structure [register ESI (x86)]
* f. bootstrap stack [register ESP (x86)]
* 5. Bootstrap elements are packed together, but each is 4kB-aligned.
* 6. The initial ram disk may be omitted.
* 7. The list of page frames forms a contiguous 'pseudo-physical' memory
* layout for the domain. In particular, the bootstrap virtual-memory
* region is a 1:1 mapping to the first section of the pseudo-physical map.
* 8. All bootstrap elements are mapped read-writeable for the guest OS. The
* only exception is the bootstrap page table, which is mapped read-only.
* 9. There is guaranteed to be at least 512kB padding after the final
* bootstrap element. If necessary, the bootstrap virtual region is
* extended by an extra 4MB to ensure this.
*/
/*
* This is the basic bootstrap information structure as passed by Xen to the
* initial controller domain. We want this structure to be easily extended by
* more sophisticated domain builders and controllers, so we make the basic
* fields of this structure available via a BASIC_START_INFO macro.
*
* Extended version of start_info_t should be defined as:
* typedef struct {
* BASIC_START_INFO;
* <...extra fields...>
* } extended_start_info_t;
*/
#define MAX_CMDLINE 256
#define BASIC_START_INFO \
/* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ \
memory_t nr_pages; /* 0: Total pages allocated to this domain. */ \
_MEMORY_PADDING(A); \
memory_t shared_info; /* 8: MACHINE address of shared info struct.*/ \
_MEMORY_PADDING(B); \
u32 flags; /* 16: SIF_xxx flags. */ \
u32 __pad; \
/* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */ \
memory_t pt_base; /* 24: VIRTUAL address of page directory. */ \
_MEMORY_PADDING(C); \
memory_t nr_pt_frames; /* 32: Number of bootstrap p.t. frames. */ \
_MEMORY_PADDING(D); \
memory_t mfn_list; /* 40: VIRTUAL address of page-frame list. */ \
_MEMORY_PADDING(E); \
memory_t mod_start; /* 48: VIRTUAL address of pre-loaded module. */ \
_MEMORY_PADDING(F); \
memory_t mod_len; /* 56: Size (bytes) of pre-loaded module. */ \
_MEMORY_PADDING(G); \
u8 cmd_line[MAX_CMDLINE] /* 64 */
typedef struct {
BASIC_START_INFO;
} PACKED start_info_t; /* 320 bytes */
/* These flags are passed in the 'flags' field of start_info_t. */
#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
/* For use in guest OSes. */
extern shared_info_t *HYPERVISOR_shared_info;
#endif /* !__ASSEMBLY__ */
#endif /* __HYPERVISOR_IF_H__ */
@@ -0,0 +1,80 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (c) 2004 - Rolf Neugebauer - Intel Research Cambridge
* (c) 2004 - Keir Fraser - University of Cambridge
****************************************************************************
* Description: Interface for domains to access physical devices on the PCI bus
*/
#ifndef __HYPERVISOR_IFS_PHYSDEV_H__
#define __HYPERVISOR_IFS_PHYSDEV_H__
/* Commands to HYPERVISOR_physdev_op() */
#define PHYSDEVOP_PCI_CFGREG_READ 0
#define PHYSDEVOP_PCI_CFGREG_WRITE 1
#define PHYSDEVOP_PCI_INITIALISE_DEVICE 2
#define PHYSDEVOP_PCI_PROBE_ROOT_BUSES 3
#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4
#define PHYSDEVOP_IRQ_STATUS_QUERY 5
/* Read from PCI configuration space. */
typedef struct {
/* IN */
u32 bus; /* 0 */
u32 dev; /* 4 */
u32 func; /* 8 */
u32 reg; /* 12 */
u32 len; /* 16 */
/* OUT */
u32 value; /* 20 */
} PACKED physdevop_pci_cfgreg_read_t; /* 24 bytes */
/* Write to PCI configuration space. */
typedef struct {
/* IN */
u32 bus; /* 0 */
u32 dev; /* 4 */
u32 func; /* 8 */
u32 reg; /* 12 */
u32 len; /* 16 */
u32 value; /* 20 */
} PACKED physdevop_pci_cfgreg_write_t; /* 24 bytes */
/* Do final initialisation of a PCI device (e.g., last-moment IRQ routing). */
typedef struct {
/* IN */
u32 bus; /* 0 */
u32 dev; /* 4 */
u32 func; /* 8 */
} PACKED physdevop_pci_initialise_device_t; /* 12 bytes */
/* Find the root buses for subsequent scanning. */
typedef struct {
/* OUT */
u32 busmask[256/32]; /* 0 */
} PACKED physdevop_pci_probe_root_buses_t; /* 32 bytes */
typedef struct {
/* IN */
u32 irq; /* 0 */
/* OUT */
/* Need to call PHYSDEVOP_IRQ_UNMASK_NOTIFY when the IRQ has been serviced? */
#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY (1<<0)
u32 flags; /* 4 */
} PACKED physdevop_irq_status_query_t; /* 8 bytes */
typedef struct _physdev_op_st
{
u32 cmd; /* 0 */
u32 __pad; /* 4 */
union { /* 8 */
physdevop_pci_cfgreg_read_t pci_cfgreg_read;
physdevop_pci_cfgreg_write_t pci_cfgreg_write;
physdevop_pci_initialise_device_t pci_initialise_device;
physdevop_pci_probe_root_buses_t pci_probe_root_buses;
physdevop_irq_status_query_t irq_status_query;
u8 __dummy[32];
} PACKED u;
} PACKED physdev_op_t; /* 40 bytes */
#endif /* __HYPERVISOR_IFS_PHYSDEV_H__ */
@@ -0,0 +1,83 @@
/**
* Generic scheduler control interface.
*
* Mark Williamson, (C) 2004 Intel Research Cambridge
*/
#ifndef __SCHED_CTL_H__
#define __SCHED_CTL_H__
/* Scheduler types */
#define SCHED_BVT 0
#define SCHED_FBVT 1
#define SCHED_ATROPOS 2
#define SCHED_RROBIN 3
/* these describe the intended direction used for a scheduler control or domain
* command */
#define SCHED_INFO_PUT 0
#define SCHED_INFO_GET 1
/*
* Generic scheduler control command - used to adjust system-wide scheduler
* parameters
*/
struct sched_ctl_cmd
{
u32 sched_id; /* 0 */
u32 direction; /* 4 */
union { /* 8 */
struct bvt_ctl
{
/* IN variables. */
u32 ctx_allow; /* 8: context switch allowance */
} PACKED bvt;
struct fbvt_ctl
{
/* IN variables. */
u32 ctx_allow; /* 8: context switch allowance */
} PACKED fbvt;
struct rrobin_ctl
{
/* IN variables */
u64 slice; /* 8: round robin time slice */
} PACKED rrobin;
} PACKED u;
} PACKED; /* 16 bytes */
struct sched_adjdom_cmd
{
u32 sched_id; /* 0 */
u32 direction; /* 4 */
domid_t domain; /* 8 */
u32 __pad;
union { /* 16 */
struct bvt_adjdom
{
u32 mcu_adv; /* 16: mcu advance: inverse of weight */
u32 warp; /* 20: time warp */
u32 warpl; /* 24: warp limit */
u32 warpu; /* 28: unwarp time requirement */
} PACKED bvt;
struct fbvt_adjdom
{
u32 mcu_adv; /* 16: mcu advance: inverse of weight */
u32 warp; /* 20: time warp */
u32 warpl; /* 24: warp limit */
u32 warpu; /* 28: unwarp time requirement */
} PACKED fbvt;
struct atropos_adjdom
{
u64 nat_period; /* 16 */
u64 nat_slice; /* 24 */
u64 latency; /* 32 */
u32 xtratime; /* 36 */
} PACKED atropos;
} PACKED u;
} PACKED; /* 40 bytes */
#endif /* __SCHED_CTL_H__ */
@@ -0,0 +1,31 @@
/******************************************************************************
* include/hypervisor-ifs/trace.h
*/
#ifndef __HYPERVISOR_IFS_TRACE_H__
#define __HYPERVISOR_IFS_TRACE_H__
/* This structure represents a single trace buffer record. */
struct t_rec {
u64 cycles; /* 64 bit cycle counter timestamp */
u32 event; /* 32 bit event ID */
u32 d1, d2, d3, d4, d5; /* event data items */
};
/*
* This structure contains the metadata for a single trace buffer. The head
* field, indexes into an array of struct t_rec's.
*/
struct t_buf {
struct t_rec *data; /* pointer to data area. physical address
* for convenience in user space code */
unsigned long size; /* size of the data area, in t_recs */
unsigned long head; /* array index of the most recent record */
/* Kernel-private elements follow... */
struct t_rec *head_ptr; /* pointer to the head record */
struct t_rec *vdata; /* virtual address pointer to data */
};
#endif /* __HYPERVISOR_IFS_TRACE_H__ */
@@ -0,0 +1,84 @@
/******************************************************************************
* multicall.h
*/
#ifndef __MULTICALL_H__
#define __MULTICALL_H__
#include <asm/hypervisor.h>
extern multicall_entry_t multicall_list[];
extern int nr_multicall_ents;
static inline void queue_multicall0(unsigned long op)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
nr_multicall_ents = i+1;
}
static inline void queue_multicall1(unsigned long op, unsigned long arg1)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
multicall_list[i].args[0] = arg1;
nr_multicall_ents = i+1;
}
static inline void queue_multicall2(
unsigned long op, unsigned long arg1, unsigned long arg2)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
multicall_list[i].args[0] = arg1;
multicall_list[i].args[1] = arg2;
nr_multicall_ents = i+1;
}
static inline void queue_multicall3(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
multicall_list[i].args[0] = arg1;
multicall_list[i].args[1] = arg2;
multicall_list[i].args[2] = arg3;
nr_multicall_ents = i+1;
}
static inline void queue_multicall4(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
multicall_list[i].args[0] = arg1;
multicall_list[i].args[1] = arg2;
multicall_list[i].args[2] = arg3;
multicall_list[i].args[3] = arg4;
nr_multicall_ents = i+1;
}
static inline void queue_multicall5(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
int i = nr_multicall_ents;
multicall_list[i].op = op;
multicall_list[i].args[0] = arg1;
multicall_list[i].args[1] = arg2;
multicall_list[i].args[2] = arg3;
multicall_list[i].args[3] = arg4;
multicall_list[i].args[4] = arg5;
nr_multicall_ents = i+1;
}
static inline void execute_multicall_list(void)
{
if ( unlikely(nr_multicall_ents == 0) ) return;
(void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents);
nr_multicall_ents = 0;
}
#endif /* __MULTICALL_H__ */
@@ -0,0 +1,88 @@
/******************************************************************************
* netif.h
*
* Unified network-device I/O interface for Xen guest OSes.
*
* Copyright (c) 2003-2004, Keir Fraser
*/
#ifndef __SHARED_NETIF_H__
#define __SHARED_NETIF_H__
typedef struct {
memory_t addr; /* 0: Machine address of packet. */
MEMORY_PADDING;
u16 id; /* 8: Echoed in response message. */
u16 size; /* 10: Packet size in bytes. */
} PACKED netif_tx_request_t; /* 12 bytes */
typedef struct {
u16 id; /* 0 */
s8 status; /* 2 */
u8 __pad; /* 3 */
} PACKED netif_tx_response_t; /* 4 bytes */
typedef struct {
u16 id; /* 0: Echoed in response message. */
} PACKED netif_rx_request_t; /* 2 bytes */
typedef struct {
memory_t addr; /* 0: Machine address of packet. */
MEMORY_PADDING;
u16 id; /* 8: */
s16 status; /* 10: -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
} PACKED netif_rx_response_t; /* 12 bytes */
/*
* We use a special capitalised type name because it is _essential_ that all
* arithmetic on indexes is done on an integer type of the correct size.
*/
typedef u32 NETIF_RING_IDX;
/*
* Ring indexes are 'free running'. That is, they are not stored modulo the
* size of the ring buffer. The following macros convert a free-running counter
* into a value that can directly index a ring-buffer array.
*/
#define MASK_NETIF_RX_IDX(_i) ((_i)&(NETIF_RX_RING_SIZE-1))
#define MASK_NETIF_TX_IDX(_i) ((_i)&(NETIF_TX_RING_SIZE-1))
#define NETIF_TX_RING_SIZE 256
#define NETIF_RX_RING_SIZE 256
/* This structure must fit in a memory page. */
typedef struct {
/*
* Frontend places packets into ring at tx_req_prod.
* Frontend receives event when tx_resp_prod passes tx_event.
*/
NETIF_RING_IDX req_prod; /* 0 */
NETIF_RING_IDX resp_prod; /* 4 */
NETIF_RING_IDX event; /* 8 */
union { /* 12 */
netif_tx_request_t req;
netif_tx_response_t resp;
} PACKED ring[NETIF_TX_RING_SIZE];
} PACKED netif_tx_interface_t;
/* This structure must fit in a memory page. */
typedef struct {
/*
* Frontend places empty buffers into ring at rx_req_prod.
* Frontend receives event when rx_resp_prod passes rx_event.
*/
NETIF_RING_IDX req_prod; /* 0 */
NETIF_RING_IDX resp_prod; /* 4 */
NETIF_RING_IDX event; /* 8 */
union { /* 12 */
netif_rx_request_t req;
netif_rx_response_t resp;
} PACKED ring[NETIF_RX_RING_SIZE];
} PACKED netif_rx_interface_t;
/* Descriptor status values */
#define NETIF_RSP_DROPPED -2
#define NETIF_RSP_ERROR -1
#define NETIF_RSP_OKAY 0
#endif
@@ -0,0 +1,3 @@
/* arch/xen/kernel/process.c */
void xen_cpu_idle (void);
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.