Commit f3081f5b authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86-64 merge

This patch depends on the i386 MTRR driver cleanup I sent earlier.

 - Support non executable mappings for x86-64. data/heap are non executable
   by default now.
 - Beginnings of software suspend from Pavel (not working yet)
 - Support generic compat functions and remove some shared code
   in the 32bit emulation (Stephen Rothwell)
 - Support hugetlbfs
 - Some makefile updates
 - Make sure all 32bit emulation functions return long, not int.
   This fixes some problems with ERESTARTNOSYS.et.al. leaking to userspace.
 - Add new system calls.
 - Fix long standing fs/gs context switch bugs (thanks to Karsten Keil
   for helping to fix that mess). Also make sure the gs selector is
   set to 0 after an exec.
 - Simplify TLS switching
 - Paranoid CPUID check at bootup
 - Reorder scatterlist to be more space efficient (Jes Soerensen)
 - Enlarge 32bit address space to full 4GB.
 - Beginnings of 32bit SYSCALL support (not completely working yet
   and vsyscall page miss yet)
 - Various merges from i386
 - New module loader
 - Support threaded core dump (XMM saving for 32bit programs doesn't
   work, but it appears to be broken on i386 too)
 - Fix bug in signal stack rounding
 - Remove DRM 32bit emulation.
 - Use MTRR driver from i386
 - Use bootflag.c from i386
 - Various other fixes and cleanups.
parent d276c772
......@@ -175,6 +175,14 @@ config MTRR
See <file:Documentation/mtrr.txt> for more information.
config HUGETLB_PAGE
bool "Huge TLB Page Support"
help
This enables support for huge pages. User space applications
can make use of this support with the hugetlbfs file system
To actually use it you need to pass an hugepages= argument
to the kernel at boot time.
config SMP
bool "Symmetric multi-processing support"
---help---
......@@ -285,6 +293,35 @@ config PM
will issue the hlt instruction if nothing is to be done, thereby
sending the processor to sleep and saving power.
config SOFTWARE_SUSPEND
bool "Software Suspend (EXPERIMENTAL)"
depends on EXPERIMENTAL && PM
---help---
Enable the possibilty of suspendig machine. It doesn't need APM.
You may suspend your machine by 'swsusp' or 'shutdown -z <time>'
(patch for sysvinit needed).
It creates an image which is saved in your active swaps. By the next
booting the, pass 'resume=/path/to/your/swap/file' and kernel will
detect the saved image, restore the memory from
it and then it continues to run as before you've suspended.
If you don't want the previous state to continue use the 'noresume'
kernel option. However note that your partitions will be fsck'd and
you must re-mkswap your swap partitions/files.
Right now you may boot without resuming and then later resume but
in meantime you cannot use those swap partitions/files which were
involved in suspending. Also in this case there is a risk that buffers
on disk won't match with saved ones.
SMP is supported ``as-is''. There's a code for it but doesn't work.
There have been problems reported relating SCSI.
This option is about getting stable. However there is still some
absence of features.
For more information take a look at Documentation/swsusp.txt.
source "drivers/acpi/Kconfig"
endmenu
......@@ -425,6 +462,11 @@ config IA32_EMULATION
turn this on, unless you're 100% sure that you don't have any 32bit programs
left.
config COMPAT
bool
depends on IA32_EMULATION
default y
endmenu
source "drivers/mtd/Kconfig"
......@@ -692,6 +734,16 @@ config KALLSYMS
symbolic stack backtraces. This increases the size of the kernel
somewhat, as all symbols have to be loaded into the kernel image.
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
depends on DEBUG_KERNEL
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.
Note this is normally not needed on x86-64.
endmenu
source "security/Kconfig"
......
......@@ -36,6 +36,7 @@ export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
LDFLAGS := -m elf_x86_64
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LDFLAGS_vmlinux := -e stext
LDFLAGS_BLOB := --format binary --oformat elf64-x86-64
CFLAGS += -mno-red-zone
CFLAGS += -mcmodel=kernel
......@@ -54,8 +55,7 @@ core-y += arch/x86_64/kernel/ arch/x86_64/mm/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
makeboot = $(call descend,arch/x86_64/boot,$(1))
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/x86_64/boot $(1)
.PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
clean archclean archmrproper
......@@ -64,21 +64,21 @@ BOOTIMAGE=arch/x86_64/boot/bzImage
zImage zlilo zdisk: BOOTIMAGE=arch/x86_64/boot/zImage
zImage bzImage: vmlinux
+@$(call makeboot,$(BOOTIMAGE))
$(call makeboot,$(BOOTIMAGE))
compressed: zImage
zlilo bzlilo: vmlinux
+@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zlilo)
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zlilo)
zdisk bzdisk: vmlinux
+@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zdisk)
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zdisk)
install: vmlinux
+@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install)
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install)
archclean:
+@$(call makeboot,clean)
$(call makeboot,clean)
archmrproper:
......
......@@ -32,10 +32,6 @@ CFLAGS += -m32
host-progs := tools/build
# Default
boot: bzImage
# ---------------------------------------------------------------------------
$(obj)/zImage: IMAGE_OFFSET := 0x1000
......@@ -62,9 +58,8 @@ $(obj)/setup $(obj)/bootsect: %: %.o FORCE
$(call if_changed,ld)
$(obj)/compressed/vmlinux: FORCE
+@$(call descend,$(obj)/compressed,IMAGE_OFFSET=$(IMAGE_OFFSET) \
$(obj)/compressed/vmlinux)
$(Q)$(MAKE) -f scripts/Makefile.build obj=$(obj)/compressed \
IMAGE_OFFSET=$(IMAGE_OFFSET) $@
zdisk: $(BOOTIMAGE)
dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
......
......@@ -18,9 +18,9 @@ LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
$(obj)/vmlinux.bin: vmlinux FORCE
strip vmlinux
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
......
......@@ -330,6 +330,8 @@ void close_output_buffer_if_we_run_high(struct moveparams *mv)
void check_cpu(void)
{
int res = 0;
int tmp, flags;
asm volatile( " \n\
movl $3,%%edx # at least 386 \n\
pushfl # push EFLAGS \n\
......@@ -395,6 +397,43 @@ void check_cpu(void)
}
if (res !=7)
error( "Sorry, your CPU is not capable of running 64-bit kernel." );
/* check required feature flags */
/* see http://www.x86-64.org/lists/discuss/msg02971.html */
#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \
(1<<13)|(1<<15)|(1<<24))
asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (0x80000001) : "ebx", "ecx");
flags &= REQUIRED_MASK1;
flags ^= REQUIRED_MASK1;
if (flags & (1<<0))
error("CPU misses x87");
if (flags & (1<<3))
error("CPU doesn't support page size extension (PSE)");
if (flags & (1<<4))
error("CPU misses an time stamp counter");
if (flags & (1<<5))
error("CPU misses AMD style MSRs");
if (flags & (1<<6))
error("CPU misses physical address extension (PAE)");
if (flags & (1<<8))
error("CPU misses cmpxchg8");
if (flags & (1<<11))
error("CPU doesn't support SYSCALL/SYSRET");
if (flags & (1<<13))
error("CPU doesn't support PGE");
if (flags & (1<<15))
error("CPU doesn't support CMOV");
if (flags & (1<<24))
error("CPU doesn't support FXSAVE/FXRSTOR");
#define REQUIRED_MASK2 ((1<<25)|(1<<26))
asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (1) : "ebx", "ecx");
flags &= REQUIRED_MASK2;
flags ^= REQUIRED_MASK2;
if (flags & (1<<25))
error("CPU doesn't support SSE1");
if (flags & (1<<26))
error("CPU doesn't support SSE2");
}
int decompress_kernel(struct moveparams *mv, void *rmode)
......
......@@ -3,11 +3,10 @@
#
CONFIG_X86_64=y
CONFIG_X86=y
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
CONFIG_MMU=y
CONFIG_SWAP=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
CONFIG_X86_CMPXCHG=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_ISA_DMA=y
......@@ -29,7 +28,9 @@ CONFIG_SYSCTL=y
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_OBSOLETE_MODPARM=y
# CONFIG_KMOD is not set
#
......@@ -43,12 +44,10 @@ CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
# CONFIG_MATH_EMULATION is not set
# CONFIG_MCA is not set
# CONFIG_EISA is not set
CONFIG_X86_IO_APIC=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_MTRR=y
CONFIG_HUGETLB_PAGE=y
CONFIG_SMP=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_NR_CPUS=8
......@@ -66,7 +65,6 @@ CONFIG_X86_MCE=y
CONFIG_ACPI=y
# CONFIG_ACPI_HT_ONLY is not set
CONFIG_ACPI_BOOT=y
# CONFIG_ACPI_SLEEP is not set
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
......@@ -75,7 +73,6 @@ CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_TOSHIBA=y
CONFIG_ACPI_DEBUG=y
CONFIG_ACPI_BOOT=y
CONFIG_ACPI_BUS=y
CONFIG_ACPI_INTERPRETER=y
CONFIG_ACPI_EC=y
......@@ -90,7 +87,6 @@ CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
#
# Executable file formats / Emulations
......@@ -99,6 +95,7 @@ CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_IA32_EMULATION=y
CONFIG_COMPAT=y
#
# Memory Technology Devices (MTD)
......@@ -114,11 +111,8 @@ CONFIG_IA32_EMULATION=y
# Block devices
#
CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
CONFIG_BLK_DEV_LOOP=y
......@@ -146,51 +140,42 @@ CONFIG_BLK_DEV_IDE=y
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_IDE_TASK_IOCTL is not set
#
# IDE chipset support/bugfixes
#
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
# CONFIG_BLK_DEV_ISAPNP is not set
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDE_TCQ is not set
# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_PCI_WIP is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_WDC_ALI15X3 is not set
CONFIG_BLK_DEV_AMD74XX=y
# CONFIG_AMD74XX_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_HPT34X_AUTODMA is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_NFORCE is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_PDC202XX_BURST is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_PDC202XX_FORCE is not set
# CONFIG_BLK_DEV_RZ1000 is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
......@@ -198,10 +183,8 @@ CONFIG_BLK_DEV_AMD74XX=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_CHIPSETS is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_IDEDMA_IVB is not set
# CONFIG_DMA_NONPCI is not set
CONFIG_BLK_DEV_IDE_MODES=y
#
......@@ -213,29 +196,15 @@ CONFIG_BLK_DEV_IDE_MODES=y
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
# CONFIG_MD_MULTIPATH is not set
# CONFIG_BLK_DEV_LVM is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_PHONE_IXJ is not set
# CONFIG_PHONE_IXJ_PCMCIA is not set
#
# Fusion MPT device support
#
# CONFIG_FUSION is not set
# CONFIG_FUSION_BOOT is not set
# CONFIG_FUSION_ISENSE is not set
# CONFIG_FUSION_CTL is not set
# CONFIG_FUSION_LAN is not set
#
# IEEE 1394 (FireWire) support (EXPERIMENTAL)
......@@ -251,6 +220,7 @@ CONFIG_NETLINK_DEV=y
# CONFIG_NETFILTER is not set
CONFIG_FILTER=y
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
......@@ -261,6 +231,9 @@ CONFIG_IP_MULTICAST=y
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_XFRM_USER is not set
# CONFIG_IPV6 is not set
#
......@@ -271,9 +244,6 @@ CONFIG_IPV6_SCTP__=y
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DEV_APPLETALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
......@@ -289,6 +259,11 @@ CONFIG_IPV6_SCTP__=y
#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
#
# Network device support
#
......@@ -308,20 +283,9 @@ CONFIG_NETDEVICES=y
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_SUNLANCE is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNBMAC is not set
# CONFIG_SUNQE is not set
# CONFIG_SUNGEM is not set
CONFIG_NET_VENDOR_3COM=y
# CONFIG_EL1 is not set
# CONFIG_EL2 is not set
# CONFIG_ELPLUS is not set
# CONFIG_EL16 is not set
# CONFIG_ELMC is not set
# CONFIG_ELMC_II is not set
CONFIG_VORTEX=y
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
......@@ -330,8 +294,27 @@ CONFIG_VORTEX=y
#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
CONFIG_8139CP=m
CONFIG_8139TOO=m
# CONFIG_8139TOO_PIO is not set
# CONFIG_8139TOO_TUNE_TWISTER is not set
# CONFIG_8139TOO_8129 is not set
# CONFIG_8139_OLD_RX_RESET is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_NET_POCKET is not set
#
......@@ -339,17 +322,16 @@ CONFIG_VORTEX=y
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
CONFIG_E1000=m
# CONFIG_E1000_NAPI is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SK98LIN is not set
CONFIG_TIGON3=y
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
......@@ -359,9 +341,8 @@ CONFIG_TIGON3=y
# CONFIG_NET_RADIO is not set
#
# Token Ring devices
# Token Ring devices (depends on LLC=y)
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
......@@ -408,17 +389,10 @@ CONFIG_INPUT_EVDEV=y
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_GAMEPORT_NS558 is not set
# CONFIG_GAMEPORT_L4 is not set
# CONFIG_GAMEPORT_EMU10K1 is not set
# CONFIG_GAMEPORT_VORTEX is not set
# CONFIG_GAMEPORT_FM801 is not set
# CONFIG_GAMEPORT_CS461x is not set
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PARKBD is not set
#
# Input Device Drivers
......@@ -431,21 +405,7 @@ CONFIG_KEYBOARD_ATKBD=y
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_INPORT is not set
# CONFIG_MOUSE_LOGIBM is not set
# CONFIG_MOUSE_PC110PAD is not set
CONFIG_INPUT_JOYSTICK=y
# CONFIG_JOYSTICK_ANALOG is not set
# CONFIG_JOYSTICK_A3D is not set
# CONFIG_JOYSTICK_ADI is not set
# CONFIG_JOYSTICK_COBRA is not set
# CONFIG_JOYSTICK_GF2K is not set
# CONFIG_JOYSTICK_GRIP is not set
# CONFIG_JOYSTICK_GRIP_MP is not set
# CONFIG_JOYSTICK_GUILLEMOT is not set
# CONFIG_JOYSTICK_INTERACT is not set
# CONFIG_JOYSTICK_SIDEWINDER is not set
# CONFIG_JOYSTICK_TMDC is not set
# CONFIG_JOYSTICK_IFORCE is not set
# CONFIG_JOYSTICK_WARRIOR is not set
# CONFIG_JOYSTICK_MAGELLAN is not set
......@@ -453,15 +413,9 @@ CONFIG_INPUT_JOYSTICK=y
# CONFIG_JOYSTICK_SPACEBALL is not set
# CONFIG_JOYSTICK_STINGER is not set
# CONFIG_JOYSTICK_TWIDDLER is not set
# CONFIG_JOYSTICK_DB9 is not set
# CONFIG_JOYSTICK_GAMECON is not set
# CONFIG_JOYSTICK_TURBOGRAFX is not set
# CONFIG_INPUT_JOYDUMP is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_INPUT_MISC is not set
# CONFIG_INPUT_PCSPKR is not set
# CONFIG_INPUT_UINPUT is not set
#
# Character devices
......@@ -476,13 +430,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_CS is not set
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250_MANY_PORTS is not set
# CONFIG_SERIAL_8250_SHARE_IRQ is not set
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
# CONFIG_SERIAL_8250_MULTIPORT is not set
# CONFIG_SERIAL_8250_RSA is not set
#
# Non-8250 serial port support
......@@ -520,17 +468,10 @@ CONFIG_RTC=y
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
CONFIG_AGP=y
# CONFIG_AGP_INTEL is not set
# CONFIG_AGP_I810 is not set
# CONFIG_AGP_VIA is not set
# CONFIG_AGP_AMD is not set
# CONFIG_AGP_SIS is not set
# CONFIG_AGP_ALI is not set
# CONFIG_AGP_SWORKS is not set
# CONFIG_AGP is not set
# CONFIG_AGP_GART is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
# CONFIG_SCx200_GPIO is not set
CONFIG_RAW_DRIVER=y
#
......@@ -546,60 +487,48 @@ CONFIG_RAW_DRIVER=y
# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
CONFIG_AUTOFS_FS=y
# CONFIG_AUTOFS4_FS is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_TMPFS=y
CONFIG_RAMFS=y
CONFIG_HUGETLBFS=y
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
# CONFIG_JFS_FS is not set
# CONFIG_JFS_DEBUG is not set
# CONFIG_JFS_STATISTICS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_DEBUG is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_XFS_FS is not set
CONFIG_XFS_FS=m
# CONFIG_XFS_RT is not set
# CONFIG_XFS_QUOTA is not set
# CONFIG_XFS_POSIX_ACL is not set
#
# Network File Systems
......@@ -609,7 +538,6 @@ CONFIG_EXT2_FS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V4 is not set
# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V4 is not set
......@@ -621,36 +549,26 @@ CONFIG_EXPORTFS=y
# CONFIG_CIFS is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
# CONFIG_NCPFS_STRONG is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_AFS_FS is not set
# CONFIG_ZISOFS_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# Console drivers
# Graphics support
#
CONFIG_VGA_CONSOLE=y
# CONFIG_FB is not set
# CONFIG_VIDEO_SELECT is not set
# CONFIG_MDA_CONSOLE is not set
#
# Frame-buffer support
# Console display driver support
#
# CONFIG_FB is not set
CONFIG_VGA_CONSOLE=y
# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
#
# Sound
......@@ -676,17 +594,20 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_CHECKING=y
# CONFIG_INIT_DEBUG is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_KALLSYMS is not set
CONFIG_KALLSYMS=y
# CONFIG_FRAME_POINTER is not set
#
# Security options
#
CONFIG_SECURITY_CAPABILITIES=y
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
# CONFIG_CRC32 is not set
# CONFIG_ZLIB_INFLATE is not set
# CONFIG_ZLIB_DEFLATE is not set
......@@ -70,6 +70,10 @@ static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
return ret;
}
struct s10 {
u64 a;
u16 b;
} __attribute__((packed));
static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
struct _fpstate_ia32 *buf)
......@@ -94,7 +98,9 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
to = (struct _fpxreg *)&fxsave->st_space[0];
from = &buf->_st[0];
for (i = 0 ; i < 8 ; i++, to++, from++) {
if (__copy_from_user(to, from, sizeof(*from)))
struct s10 *top = (void *)to, *fromp = (void *)from;
if (__put_user(fromp->a, &top->a) ||
__put_user(fromp->b, &top->b))
return -1;
}
return 0;
......@@ -130,7 +136,9 @@ static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf,
to = &buf->_st[0];
from = (struct _fpxreg *) &fxsave->st_space[0];
for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
if (__copy_to_user(to, from, sizeof(*to)))
struct s10 *top = (void *)top, *fromp = (void *)from;
if (__get_user(fromp->a, &top->a) ||
__get_user(fromp->b, &top->b))
return -1;
}
return 0;
......
......@@ -6,12 +6,13 @@
* of ugly preprocessor tricks. Talk about very very poor man's inheritance.
*/
#include <linux/types.h>
#include <linux/compat.h>
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/rwsem.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/binfmts.h>
#include <asm/segment.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
......@@ -19,14 +20,14 @@
#include <asm/sigcontext32.h>
#include <asm/fpu32.h>
#include <asm/i387.h>
#include <asm/uaccess.h>
#include <asm/ia32.h>
struct file;
struct elf_phdr;
#define IA32_EMULATOR 1
#define IA32_PAGE_OFFSET 0xffff0000
#define IA32_STACK_TOP IA32_PAGE_OFFSET
#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000)
#undef ELF_ARCH
......@@ -53,11 +54,6 @@ struct elf_siginfo
int si_errno; /* errno */
};
struct timeval32
{
int tv_sec, tv_usec;
};
#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
struct elf_prstatus
......@@ -70,10 +66,10 @@ struct elf_prstatus
pid_t pr_ppid;
pid_t pr_pgrp;
pid_t pr_sid;
struct timeval32 pr_utime; /* User time */
struct timeval32 pr_stime; /* System time */
struct timeval32 pr_cutime; /* Cumulative user time */
struct timeval32 pr_cstime; /* Cumulative system time */
struct compat_timeval pr_utime; /* User time */
struct compat_timeval pr_stime; /* System time */
struct compat_timeval pr_cutime; /* Cumulative user time */
struct compat_timeval pr_cstime; /* Cumulative system time */
elf_gregset_t pr_reg; /* GP registers */
int pr_fpvalid; /* True if math co-processor being used. */
};
......@@ -123,15 +119,68 @@ struct elf_prpsinfo
#define user user32
#define dump_fpu dump_fpu_ia32
#define __ASM_X86_64_ELF_H 1
#include <asm/ia32.h>
//#include <asm/ia32.h>
#include <linux/elf.h>
typedef struct user_i387_ia32_struct elf_fpregset_t;
typedef struct user32_fxsr_struct elf_fpxregset_t;
static inline void elf_core_copy_regs(elf_gregset_t *elfregs, struct pt_regs *regs)
{
ELF_CORE_COPY_REGS((*elfregs), regs)
}
static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* elfregs)
{
struct pt_regs *pp = (struct pt_regs *)(t->thread.rsp0);
ELF_CORE_COPY_REGS((*elfregs), pp);
/* fix wrong segments */
(*elfregs)[7] = t->thread.ds;
(*elfregs)[9] = t->thread.fsindex;
(*elfregs)[10] = t->thread.gsindex;
(*elfregs)[8] = t->thread.es;
return 1;
}
static inline int
elf_core_copy_task_fpregs(struct task_struct *tsk, elf_fpregset_t *fpu)
{
struct _fpstate_ia32 *fpstate = (void*)fpu;
struct pt_regs *regs = (struct pt_regs *)(tsk->thread.rsp0);
mm_segment_t oldfs = get_fs();
int ret;
if (!tsk->used_math)
return 0;
--regs;
if (tsk == current)
unlazy_fpu(tsk);
set_fs(KERNEL_DS);
ret = save_i387_ia32(tsk, fpstate, regs, 1);
/* Correct for i386 bug. It puts the fop into the upper 16bits of
the tag word (like FXSAVE), not into the fcs*/
fpstate->cssel |= fpstate->tag & 0xffff0000;
set_fs(oldfs);
return ret;
}
#define ELF_CORE_COPY_XFPREGS 1
static inline int
elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
{
struct pt_regs *regs = ((struct pt_regs *)(t->thread.rsp0))-1;
if (!t->used_math)
return 0;
if (t == current)
unlazy_fpu(t);
memcpy(xfpu, &t->thread.i387.fxsave, sizeof(elf_fpxregset_t));
xfpu->fcs = regs->cs;
xfpu->fos = t->thread.ds; /* right? */
return 1;
}
#undef elf_check_arch
#define elf_check_arch(x) \
((x)->e_machine == EM_386)
......@@ -168,9 +217,9 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm);
#undef start_thread
#define start_thread(regs,new_rip,new_rsp) do { \
__asm__("movl %0,%%fs": :"r" (0)); \
__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
wrmsrl(MSR_KERNEL_GS_BASE, 0); \
asm volatile("movl %0,%%fs" :: "r" (0)); \
asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
load_gs_index(0); \
(regs)->rip = (new_rip); \
(regs)->rsp = (new_rsp); \
(regs)->eflags = 0x200; \
......@@ -182,6 +231,8 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm);
#define elf_map elf32_map
#include <linux/module.h>
MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries.");
MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
......@@ -245,7 +296,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_mm = mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = IA32_STACK_TOP;
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_page_prot = PAGE_COPY_EXEC;
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL;
mpnt->vm_pgoff = 0;
......@@ -287,23 +338,3 @@ elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int p
return(map_addr);
}
int dump_fpu_ia32(struct pt_regs *regs, elf_fpregset_t *fp)
{
struct _fpstate_ia32 *fpu = (void*)fp;
struct task_struct *tsk = current;
mm_segment_t oldfs = get_fs();
int ret;
if (!tsk->used_math)
return 0;
if (!(test_thread_flag(TIF_IA32)))
BUG();
unlazy_fpu(tsk);
set_fs(KERNEL_DS);
ret = save_i387_ia32(current, fpu, regs, 1);
/* Correct for i386 bug. It puts the fop into the upper 16bits of
the tag word (like FXSAVE), not into the fcs*/
fpu->cssel |= fpu->tag & 0xffff0000;
set_fs(oldfs);
return ret;
}
......@@ -11,6 +11,7 @@
#include <linux/config.h>
#include <linux/types.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
......@@ -405,14 +406,9 @@ static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
}
struct timeval32 {
int tv_sec;
int tv_usec;
};
static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct timeval32 *up = (struct timeval32 *)arg;
struct compat_timeval *up = (struct compat_timeval *)arg;
struct timeval ktv;
mm_segment_t old_fs = get_fs();
int err;
......@@ -1611,8 +1607,8 @@ struct ppp_option_data32 {
#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
struct ppp_idle32 {
__kernel_time_t32 xmit_idle;
__kernel_time_t32 recv_idle;
compat_time_t xmit_idle;
compat_time_t recv_idle;
};
#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
......@@ -1913,9 +1909,9 @@ out: if (data)
struct loop_info32 {
int lo_number; /* ioctl r/o */
__kernel_dev_t32 lo_device; /* ioctl r/o */
compat_dev_t lo_device; /* ioctl r/o */
unsigned int lo_inode; /* ioctl r/o */
__kernel_dev_t32 lo_rdevice; /* ioctl r/o */
compat_dev_t lo_rdevice; /* ioctl r/o */
int lo_offset;
int lo_encrypt_type;
int lo_encrypt_key_size; /* ioctl w/o */
......@@ -2120,7 +2116,7 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a
set_fs(old_fs);
if (err >= 0)
err = put_user(kuid, (__kernel_uid_t32 *)arg);
err = put_user(kuid, (compat_pid_t *)arg);
return err;
}
......@@ -2779,543 +2775,6 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
}
#endif
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
/* This really belongs in include/linux/drm.h -DaveM */
#include "../../../drivers/char/drm/drm.h"
typedef struct drm32_version {
int version_major; /* Major version */
int version_minor; /* Minor version */
int version_patchlevel;/* Patch level */
int name_len; /* Length of name buffer */
u32 name; /* Name of driver */
int date_len; /* Length of date buffer */
u32 date; /* User-space buffer to hold date */
int desc_len; /* Length of desc buffer */
u32 desc; /* User-space buffer to hold desc */
} drm32_version_t;
#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t)
static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_version_t *uversion = (drm32_version_t *)arg;
char *name_ptr, *date_ptr, *desc_ptr;
u32 tmp1, tmp2, tmp3;
drm_version_t kversion;
mm_segment_t old_fs;
int ret;
memset(&kversion, 0, sizeof(kversion));
if (get_user(kversion.name_len, &uversion->name_len) ||
get_user(kversion.date_len, &uversion->date_len) ||
get_user(kversion.desc_len, &uversion->desc_len) ||
get_user(tmp1, &uversion->name) ||
get_user(tmp2, &uversion->date) ||
get_user(tmp3, &uversion->desc))
return -EFAULT;
name_ptr = (char *) A(tmp1);
date_ptr = (char *) A(tmp2);
desc_ptr = (char *) A(tmp3);
ret = -ENOMEM;
if (kversion.name_len && name_ptr) {
kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
if (!kversion.name)
goto out;
}
if (kversion.date_len && date_ptr) {
kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
if (!kversion.date)
goto out;
}
if (kversion.desc_len && desc_ptr) {
kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
if (!kversion.desc)
goto out;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
set_fs(old_fs);
if (!ret) {
if ((kversion.name &&
copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
(kversion.date &&
copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
(kversion.desc &&
copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
ret = -EFAULT;
if (put_user(kversion.version_major, &uversion->version_major) ||
put_user(kversion.version_minor, &uversion->version_minor) ||
put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
put_user(kversion.name_len, &uversion->name_len) ||
put_user(kversion.date_len, &uversion->date_len) ||
put_user(kversion.desc_len, &uversion->desc_len))
ret = -EFAULT;
}
out:
if (kversion.name)
kfree(kversion.name);
if (kversion.date)
kfree(kversion.date);
if (kversion.desc)
kfree(kversion.desc);
return ret;
}
typedef struct drm32_unique {
int unique_len; /* Length of unique */
u32 unique; /* Unique name for driver instantiation */
} drm32_unique_t;
#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_unique_t *uarg = (drm32_unique_t *)arg;
drm_unique_t karg;
mm_segment_t old_fs;
char *uptr;
u32 tmp;
int ret;
if (get_user(karg.unique_len, &uarg->unique_len))
return -EFAULT;
karg.unique = NULL;
if (get_user(tmp, &uarg->unique))
return -EFAULT;
uptr = (char *) A(tmp);
if (uptr) {
karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
if (!karg.unique)
return -ENOMEM;
if (cmd == DRM32_IOCTL_SET_UNIQUE &&
copy_from_user(karg.unique, uptr, karg.unique_len)) {
kfree(karg.unique);
return -EFAULT;
}
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (cmd == DRM32_IOCTL_GET_UNIQUE)
ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
else
ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
set_fs(old_fs);
if (!ret) {
if (cmd == DRM32_IOCTL_GET_UNIQUE &&
uptr != NULL &&
copy_to_user(uptr, karg.unique, karg.unique_len))
ret = -EFAULT;
if (put_user(karg.unique_len, &uarg->unique_len))
ret = -EFAULT;
}
if (karg.unique != NULL)
kfree(karg.unique);
return ret;
}
typedef struct drm32_map {
u32 offset; /* Requested physical address (0 for SAREA)*/
u32 size; /* Requested physical size (bytes) */
drm_map_type_t type; /* Type of memory to map */
drm_map_flags_t flags; /* Flags */
u32 handle; /* User-space: "Handle" to pass to mmap */
/* Kernel-space: kernel-virtual address */
int mtrr; /* MTRR slot used */
/* Private data */
} drm32_map_t;
#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t)
static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_map_t *uarg = (drm32_map_t *) arg;
drm_map_t karg;
mm_segment_t old_fs;
u32 tmp;
int ret;
ret = get_user(karg.offset, &uarg->offset);
ret |= get_user(karg.size, &uarg->size);
ret |= get_user(karg.type, &uarg->type);
ret |= get_user(karg.flags, &uarg->flags);
ret |= get_user(tmp, &uarg->handle);
ret |= get_user(karg.mtrr, &uarg->mtrr);
if (ret)
return -EFAULT;
karg.handle = (void *) A(tmp);
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
ret = put_user(karg.offset, &uarg->offset);
ret |= put_user(karg.size, &uarg->size);
ret |= put_user(karg.type, &uarg->type);
ret |= put_user(karg.flags, &uarg->flags);
tmp = (u32) (long)karg.handle;
ret |= put_user(tmp, &uarg->handle);
ret |= put_user(karg.mtrr, &uarg->mtrr);
if (ret)
ret = -EFAULT;
}
return ret;
}
typedef struct drm32_buf_info {
int count; /* Entries in list */
u32 list; /* (drm_buf_desc_t *) */
} drm32_buf_info_t;
#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t)
static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
drm_buf_desc_t *ulist;
drm_buf_info_t karg;
mm_segment_t old_fs;
int orig_count, ret;
u32 tmp;
if (get_user(karg.count, &uarg->count) ||
get_user(tmp, &uarg->list))
return -EFAULT;
ulist = (drm_buf_desc_t *) A(tmp);
orig_count = karg.count;
karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
if (!karg.list)
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
if (karg.count <= orig_count &&
(copy_to_user(ulist, karg.list,
karg.count * sizeof(drm_buf_desc_t))))
ret = -EFAULT;
if (put_user(karg.count, &uarg->count))
ret = -EFAULT;
}
kfree(karg.list);
return ret;
}
typedef struct drm32_buf_free {
int count;
u32 list; /* (int *) */
} drm32_buf_free_t;
#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t)
static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
drm_buf_free_t karg;
mm_segment_t old_fs;
int *ulist;
int ret;
u32 tmp;
if (get_user(karg.count, &uarg->count) ||
get_user(tmp, &uarg->list))
return -EFAULT;
ulist = (int *) A(tmp);
karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
if (!karg.list)
return -ENOMEM;
ret = -EFAULT;
if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
goto out;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
set_fs(old_fs);
out:
kfree(karg.list);
return ret;
}
typedef struct drm32_buf_pub {
int idx; /* Index into master buflist */
int total; /* Buffer size */
int used; /* Amount of buffer in use (for DMA) */
u32 address; /* Address of buffer (void *) */
} drm32_buf_pub_t;
typedef struct drm32_buf_map {
int count; /* Length of buflist */
u32 virtual; /* Mmaped area in user-virtual (void *) */
u32 list; /* Buffer information (drm_buf_pub_t *) */
} drm32_buf_map_t;
#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t)
static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
drm32_buf_pub_t *ulist;
drm_buf_map_t karg;
mm_segment_t old_fs;
int orig_count, ret, i;
u32 tmp1, tmp2;
if (get_user(karg.count, &uarg->count) ||
get_user(tmp1, &uarg->virtual) ||
get_user(tmp2, &uarg->list))
return -EFAULT;
karg.virtual = (void *) A(tmp1);
ulist = (drm32_buf_pub_t *) A(tmp2);
orig_count = karg.count;
karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
if (!karg.list)
return -ENOMEM;
ret = -EFAULT;
for (i = 0; i < karg.count; i++) {
if (get_user(karg.list[i].idx, &ulist[i].idx) ||
get_user(karg.list[i].total, &ulist[i].total) ||
get_user(karg.list[i].used, &ulist[i].used) ||
get_user(tmp1, &ulist[i].address))
goto out;
karg.list[i].address = (void *) A(tmp1);
}
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
for (i = 0; i < orig_count; i++) {
tmp1 = (u32) (long) karg.list[i].address;
if (put_user(karg.list[i].idx, &ulist[i].idx) ||
put_user(karg.list[i].total, &ulist[i].total) ||
put_user(karg.list[i].used, &ulist[i].used) ||
put_user(tmp1, &ulist[i].address)) {
ret = -EFAULT;
goto out;
}
}
if (put_user(karg.count, &uarg->count))
ret = -EFAULT;
}
out:
kfree(karg.list);
return ret;
}
typedef struct drm32_dma {
/* Indices here refer to the offset into
buflist in drm_buf_get_t. */
int context; /* Context handle */
int send_count; /* Number of buffers to send */
u32 send_indices; /* List of handles to buffers (int *) */
u32 send_sizes; /* Lengths of data to send (int *) */
drm_dma_flags_t flags; /* Flags */
int request_count; /* Number of buffers requested */
int request_size; /* Desired size for buffers */
u32 request_indices; /* Buffer information (int *) */
u32 request_sizes; /* (int *) */
int granted_count; /* Number of buffers granted */
} drm32_dma_t;
#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t)
/* RED PEN The DRM layer blindly dereferences the send/request
* indice/size arrays even though they are userland
* pointers. -DaveM
*/
static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_dma_t *uarg = (drm32_dma_t *) arg;
int *u_si, *u_ss, *u_ri, *u_rs;
drm_dma_t karg;
mm_segment_t old_fs;
int ret;
u32 tmp1, tmp2, tmp3, tmp4;
karg.send_indices = karg.send_sizes = NULL;
karg.request_indices = karg.request_sizes = NULL;
if (get_user(karg.context, &uarg->context) ||
get_user(karg.send_count, &uarg->send_count) ||
get_user(tmp1, &uarg->send_indices) ||
get_user(tmp2, &uarg->send_sizes) ||
get_user(karg.flags, &uarg->flags) ||
get_user(karg.request_count, &uarg->request_count) ||
get_user(karg.request_size, &uarg->request_size) ||
get_user(tmp3, &uarg->request_indices) ||
get_user(tmp4, &uarg->request_sizes) ||
get_user(karg.granted_count, &uarg->granted_count))
return -EFAULT;
u_si = (int *) A(tmp1);
u_ss = (int *) A(tmp2);
u_ri = (int *) A(tmp3);
u_rs = (int *) A(tmp4);
if (karg.send_count) {
karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
ret = -ENOMEM;
if (!karg.send_indices || !karg.send_sizes)
goto out;
ret = -EFAULT;
if (copy_from_user(karg.send_indices, u_si,
(karg.send_count * sizeof(int))) ||
copy_from_user(karg.send_sizes, u_ss,
(karg.send_count * sizeof(int))))
goto out;
}
if (karg.request_count) {
karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
ret = -ENOMEM;
if (!karg.request_indices || !karg.request_sizes)
goto out;
ret = -EFAULT;
if (copy_from_user(karg.request_indices, u_ri,
(karg.request_count * sizeof(int))) ||
copy_from_user(karg.request_sizes, u_rs,
(karg.request_count * sizeof(int))))
goto out;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
if (put_user(karg.context, &uarg->context) ||
put_user(karg.send_count, &uarg->send_count) ||
put_user(karg.flags, &uarg->flags) ||
put_user(karg.request_count, &uarg->request_count) ||
put_user(karg.request_size, &uarg->request_size) ||
put_user(karg.granted_count, &uarg->granted_count))
ret = -EFAULT;
if (karg.send_count) {
if (copy_to_user(u_si, karg.send_indices,
(karg.send_count * sizeof(int))) ||
copy_to_user(u_ss, karg.send_sizes,
(karg.send_count * sizeof(int))))
ret = -EFAULT;
}
if (karg.request_count) {
if (copy_to_user(u_ri, karg.request_indices,
(karg.request_count * sizeof(int))) ||
copy_to_user(u_rs, karg.request_sizes,
(karg.request_count * sizeof(int))))
ret = -EFAULT;
}
}
out:
if (karg.send_indices)
kfree(karg.send_indices);
if (karg.send_sizes)
kfree(karg.send_sizes);
if (karg.request_indices)
kfree(karg.request_indices);
if (karg.request_sizes)
kfree(karg.request_sizes);
return ret;
}
typedef struct drm32_ctx_res {
int count;
u32 contexts; /* (drm_ctx_t *) */
} drm32_ctx_res_t;
#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t)
static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
drm_ctx_t *ulist;
drm_ctx_res_t karg;
mm_segment_t old_fs;
int orig_count, ret;
u32 tmp;
karg.contexts = NULL;
if (get_user(karg.count, &uarg->count) ||
get_user(tmp, &uarg->contexts))
return -EFAULT;
ulist = (drm_ctx_t *) A(tmp);
orig_count = karg.count;
if (karg.count && ulist) {
karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
if (!karg.contexts)
return -ENOMEM;
if (copy_from_user(karg.contexts, ulist,
(karg.count * sizeof(drm_ctx_t)))) {
kfree(karg.contexts);
return -EFAULT;
}
}
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
if (orig_count) {
if (copy_to_user(ulist, karg.contexts,
(orig_count * sizeof(drm_ctx_t))))
ret = -EFAULT;
}
if (put_user(karg.count, &uarg->count))
ret = -EFAULT;
}
if (karg.contexts)
kfree(karg.contexts);
return ret;
}
#endif
static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
{
......@@ -3491,7 +2950,7 @@ static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr)
struct dirent32 {
unsigned int d_ino;
__kernel_off_t32 d_off;
compat_off_t d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};
......@@ -4189,11 +3648,6 @@ COMPATIBLE_IOCTL(TIOCSERGETLSR)
COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO)
COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO)
COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO)
COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE)
COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE)
COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
/* Little f */
......@@ -4696,27 +4150,6 @@ COMPATIBLE_IOCTL(LE_REMAP)
COMPATIBLE_IOCTL(LV_BMAP)
COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
#endif /* LVM */
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
#endif /* DRM */
#ifdef CONFIG_AUTOFS_FS
COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
......@@ -4941,7 +4374,7 @@ HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
/* One SMB ioctl needs translations. */
#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_pid_t)
HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
......@@ -4984,17 +4417,6 @@ HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
#endif /* LVM */
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version)
HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique)
HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique)
HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap)
HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs)
HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs)
HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs)
HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma)
HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx)
#endif /* DRM */
/* VFAT */
HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
......@@ -5179,7 +4601,7 @@ int unregister_ioctl32_conversion(unsigned int cmd)
EXPORT_SYMBOL(register_ioctl32_conversion);
EXPORT_SYMBOL(unregister_ioctl32_conversion);
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
asmlinkage long sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
int error = -EBADF;
......
......@@ -76,7 +76,7 @@ static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from)
}
}
asmlinkage int
asmlinkage long
sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
{
sigset_t saveset;
......@@ -97,7 +97,7 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r
}
}
asmlinkage int
asmlinkage long
sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr,
struct pt_regs regs)
{
......@@ -227,7 +227,7 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign
return 1;
}
asmlinkage int sys32_sigreturn(struct pt_regs regs)
asmlinkage long sys32_sigreturn(struct pt_regs regs)
{
struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
sigset_t set;
......@@ -256,7 +256,7 @@ asmlinkage int sys32_sigreturn(struct pt_regs regs)
return 0;
}
asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
{
struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
sigset_t set;
......
/*
* Compatibility mode system call entry point for x86-64.
*
* Copyright 2000,2001 Andi Kleen, SuSE Labs.
* Copyright 2000-2002 Andi Kleen, SuSE Labs.
*
* $Id: ia32entry.S,v 1.31 2002/03/24 13:01:45 ak Exp $
*/
......@@ -9,10 +9,11 @@
#include <asm/calling.h>
#include <asm/offset.h>
#include <asm/current.h>
#include <linux/linkage.h>
#include <asm/errno.h>
#include <asm/ia32_unistd.h>
#include <asm/thread_info.h>
#include <asm/segment.h>
#include <linux/linkage.h>
.macro IA32_ARG_FIXUP
movl %edi,%r8d
......@@ -23,12 +24,73 @@
.endm
/*
* 32bit SYSCALL instruction entry.
* 32bit SYSCALL instruction entry. This is called from the 32bit vsyscall page.
*
* Register setup:
*
* %eax System call number.
* %ebx Arg1
* %ecx return EIP
* %edx Arg3
* %esi Arg4
* %edi Arg5
* %ebp Arg2 [note: not saved in the stack frame, should not be touched]
* %esp user stack
* 0(%esp) Arg6
*
* Interrupts off.
*
* This is purely a fast path. For anything complicated we use the int 0x80
* path below. Set up a complete hardware stack frame to share code
* with the int 0x80 path.
*/
ENTRY(ia32_cstar_target)
movq $-ENOSYS,%rax
swapgs
movl %esp,%r8d
movq %gs:pda_kernelstack,%rsp
sti
SAVE_ARGS 8,1
movl %eax,%eax /* zero extension */
movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
movq %rcx,RIP-ARGOFFSET(%rsp)
movl %ebp,%ecx
movq $__USER32_CS,CS-ARGOFFSET(%rsp)
movq $__USER32_DS,SS-ARGOFFSET(%rsp)
movq %r11,EFLAGS-ARGOFFSET(%rsp)
movq %r8,RSP-ARGOFFSET(%rsp)
/* no need to do an access_ok check here because the 32bit
user space cannot set r8 to a value > 4GB and the kernel has no
memory mapping in the first 4GB. */
/* hardware stack frame is complete now */
1: movl (%r8),%ebp
.section __ex_table,"a"
.quad 1b,cstar_badarg
.previous
GET_THREAD_INFO(%r10)
bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
jc ia32_tracesys
cmpl $IA32_NR_syscalls,%eax
jae ia32_badsys
IA32_ARG_FIXUP
call *ia32_sys_call_table(,%rax,8)
.globl ia32_sysret
cstar_sysret:
movq %rax,RAX-ARGOFFSET(%rsp)
GET_THREAD_INFO(%r10)
cli
testl $_TIF_WORK_MASK,threadinfo_flags(%r10)
jnz int_ret_from_sys_call
RESTORE_ARGS 1,0,1,1 /* could avoid the stack restore here */
movl RIP-SWFRAME(%rsp),%ecx
movl RSP-SWFRAME(%rsp),%esp
movl EFLAGS-SWFRAME(%rsp),%r11d
swapgs
sysretl
cstar_badarg:
movq $-EFAULT,%rax
jmp cstar_sysret
/*
* Emulated IA32 system calls via int 0x80.
*
......@@ -121,7 +183,7 @@ ENTRY(ia32_ptregs_common)
.align 8
.globl ia32_sys_call_table
ia32_sys_call_table:
.quad ni_syscall /* 0 - old "setup" system call*/
.quad sys_restart_syscall
.quad sys_exit
.quad stub32_fork
.quad sys_read
......@@ -151,7 +213,7 @@ ia32_sys_call_table:
.quad sys_alarm /* XXX sign extension??? */
.quad ni_syscall /* (old)fstat */
.quad sys_pause
.quad sys32_utime /* 30 */
.quad compat_sys_utime /* 30 */
.quad ni_syscall /* old stty syscall holder */
.quad ni_syscall /* old gtty syscall holder */
.quad sys_access
......@@ -164,7 +226,7 @@ ia32_sys_call_table:
.quad sys_rmdir /* 40 */
.quad sys_dup
.quad sys32_pipe
.quad sys32_times
.quad compat_sys_times
.quad ni_syscall /* old prof syscall holder */
.quad sys_brk /* 45 */
.quad sys_setgid16
......@@ -225,11 +287,11 @@ ia32_sys_call_table:
.quad sys_ioperm
.quad sys32_socketcall
.quad sys_syslog
.quad sys32_setitimer
.quad sys32_getitimer /* 105 */
.quad sys32_newstat
.quad sys32_newlstat
.quad sys32_newfstat
.quad compat_sys_setitimer
.quad compat_sys_getitimer /* 105 */
.quad compat_sys_newstat
.quad compat_sys_newlstat
.quad compat_sys_newfstat
.quad sys32_uname
.quad stub32_iopl /* 110 */
.quad sys_vhangup
......@@ -283,7 +345,7 @@ ia32_sys_call_table:
.quad sys_sched_get_priority_max
.quad sys_sched_get_priority_min /* 160 */
.quad sys_sched_rr_get_interval
.quad sys32_nanosleep
.quad compat_sys_nanosleep
.quad sys_mremap
.quad sys_setresuid16
.quad sys_getresuid16 /* 165 */
......@@ -361,7 +423,7 @@ ia32_sys_call_table:
.quad sys_fremovexattr
.quad sys_tkill /* 238 */
.quad sys_sendfile64
.quad sys_futex /* 240 */
.quad sys32_futex /* 240 */
.quad sys32_sched_setaffinity
.quad sys32_sched_getaffinity
.quad sys_set_thread_area
......@@ -374,6 +436,14 @@ ia32_sys_call_table:
.quad sys_ni_syscall /* 250 alloc_huge_pages */
.quad sys_ni_syscall /* free_huge_pages */
.quad sys_exit_group /* exit_group */
.quad sys_lookup_dcookie
.quad sys_epoll_create
.quad sys_epoll_ctl
.quad sys_epoll_wait
.quad sys_remap_file_pages
.quad sys_set_tid_address
/* don't forget to change IA32_NR_syscalls */
ia32_syscall_end:
.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
.quad ni_syscall
......
......@@ -8,6 +8,7 @@
#include <linux/shm.h>
#include <linux/slab.h>
#include <linux/ipc.h>
#include <linux/compat.h>
#include <asm/mman.h>
#include <asm/types.h>
#include <asm/uaccess.h>
......@@ -29,10 +30,10 @@ struct msgbuf32 {
struct ipc_perm32 {
int key;
__kernel_uid_t32 uid;
__kernel_gid_t32 gid;
__kernel_uid_t32 cuid;
__kernel_gid_t32 cgid;
compat_uid_t uid;
compat_gid_t gid;
compat_uid_t cuid;
compat_gid_t cgid;
unsigned short mode;
unsigned short seq;
};
......@@ -53,8 +54,8 @@ struct ipc64_perm32 {
struct semid_ds32 {
struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
__kernel_time_t32 sem_otime; /* last semop time */
__kernel_time_t32 sem_ctime; /* last change time */
compat_time_t sem_otime; /* last semop time */
compat_time_t sem_ctime; /* last change time */
u32 sem_base; /* ptr to first semaphore in array */
u32 sem_pending; /* pending operations to be processed */
u32 sem_pending_last; /* last pending operation */
......@@ -64,9 +65,9 @@ struct semid_ds32 {
struct semid64_ds32 {
struct ipc64_perm32 sem_perm;
__kernel_time_t32 sem_otime;
compat_time_t sem_otime;
unsigned int __unused1;
__kernel_time_t32 sem_ctime;
compat_time_t sem_ctime;
unsigned int __unused2;
unsigned int sem_nsems;
unsigned int __unused3;
......@@ -77,9 +78,9 @@ struct msqid_ds32 {
struct ipc_perm32 msg_perm;
u32 msg_first;
u32 msg_last;
__kernel_time_t32 msg_stime;
__kernel_time_t32 msg_rtime;
__kernel_time_t32 msg_ctime;
compat_time_t msg_stime;
compat_time_t msg_rtime;
compat_time_t msg_ctime;
u32 wwait;
u32 rwait;
unsigned short msg_cbytes;
......@@ -91,17 +92,17 @@ struct msqid_ds32 {
struct msqid64_ds32 {
struct ipc64_perm32 msg_perm;
__kernel_time_t32 msg_stime;
compat_time_t msg_stime;
unsigned int __unused1;
__kernel_time_t32 msg_rtime;
compat_time_t msg_rtime;
unsigned int __unused2;
__kernel_time_t32 msg_ctime;
compat_time_t msg_ctime;
unsigned int __unused3;
unsigned int msg_cbytes;
unsigned int msg_qnum;
unsigned int msg_qbytes;
__kernel_pid_t32 msg_lspid;
__kernel_pid_t32 msg_lrpid;
compat_pid_t msg_lspid;
compat_pid_t msg_lrpid;
unsigned int __unused4;
unsigned int __unused5;
};
......@@ -109,9 +110,9 @@ struct msqid64_ds32 {
struct shmid_ds32 {
struct ipc_perm32 shm_perm;
int shm_segsz;
__kernel_time_t32 shm_atime;
__kernel_time_t32 shm_dtime;
__kernel_time_t32 shm_ctime;
compat_time_t shm_atime;
compat_time_t shm_dtime;
compat_time_t shm_ctime;
__kernel_ipc_pid_t32 shm_cpid;
__kernel_ipc_pid_t32 shm_lpid;
unsigned short shm_nattch;
......@@ -119,15 +120,15 @@ struct shmid_ds32 {
struct shmid64_ds32 {
struct ipc64_perm32 shm_perm;
__kernel_size_t32 shm_segsz;
__kernel_time_t32 shm_atime;
compat_size_t shm_segsz;
compat_time_t shm_atime;
unsigned int __unused1;
__kernel_time_t32 shm_dtime;
compat_time_t shm_dtime;
unsigned int __unused2;
__kernel_time_t32 shm_ctime;
compat_time_t shm_ctime;
unsigned int __unused3;
__kernel_pid_t32 shm_cpid;
__kernel_pid_t32 shm_lpid;
compat_pid_t shm_cpid;
compat_pid_t shm_lpid;
unsigned int shm_nattch;
unsigned int __unused4;
unsigned int __unused5;
......@@ -163,6 +164,7 @@ struct ipc_kludge {
#define SEMOP 1
#define SEMGET 2
#define SEMCTL 3
#define TIMEDSEMOP 4
#define MSGSND 11
#define MSGRCV 12
#define MSGGET 13
......@@ -622,7 +624,12 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
switch (call) {
case SEMOP:
/* struct sembuf is the same on 32 and 64bit :)) */
return sys_semop(first, (struct sembuf *)AA(ptr), second);
return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
NULL);
case TIMEDSEMOP:
/* struct sembuf is the same on 32 and 64bit :)) */
return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
(const struct timespec *)AA(fifth));
case SEMGET:
return sys_semget(first, second, third);
case SEMCTL:
......@@ -646,7 +653,6 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
return sys_shmget(first, second, third);
case SHMCTL:
return shmctl32(first, second, (void *)AA(ptr));
default:
return -EINVAL;
}
......
......@@ -19,6 +19,7 @@
#include <linux/icmpv6.h>
#include <linux/socket.h>
#include <linux/filter.h>
#include <linux/compat.h>
#include <net/scm.h>
#include <net/sock.h>
......@@ -29,6 +30,9 @@
#define A(__x) ((unsigned long)(__x))
#define AA(__x) ((unsigned long)(__x))
extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
void * optval, int *optlen);
static inline int iov_from_user32_to_kern(struct iovec *kiov,
struct iovec32 *uiov32,
......@@ -123,7 +127,7 @@ static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
{
struct cmsghdr32 *ucmsg;
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
compat_size_t ucmlen;
__kernel_size_t kcmlen, tmp;
kcmlen = 0;
......@@ -362,7 +366,7 @@ static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_up
kmsg->msg_control = (void *) orig_cmsg_uptr;
}
asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
......@@ -407,7 +411,7 @@ asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_fl
return err;
}
asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
{
struct iovec iovstack[UIO_FASTIOV];
struct msghdr kern_msg;
......@@ -489,7 +493,7 @@ asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int use
err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
if(cmsg_ptr != 0 && err >= 0) {
unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
compat_size_t uclen = (compat_size_t) (ucmsg_ptr - cmsg_ptr);
err |= __put_user(uclen, &user_msg->msg_controllen);
}
if(err >= 0)
......@@ -575,12 +579,34 @@ static int do_set_icmpv6_filter(int fd, int level, int optname,
return ret;
}
asmlinkage int sys32_setsockopt(int fd, int level, int optname,
static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int optlen)
{
struct compat_timeval *up = (struct compat_timeval *) optval;
struct timeval ktime;
mm_segment_t old_fs;
int err;
if (optlen < sizeof(*up))
return -EINVAL;
if (get_user(ktime.tv_sec, &up->tv_sec) ||
__get_user(ktime.tv_usec, &up->tv_usec))
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime));
set_fs(old_fs);
return err;
}
asmlinkage long sys32_setsockopt(int fd, int level, int optname,
char *optval, int optlen)
{
if (optname == SO_ATTACH_FILTER)
return do_set_attach_filter(fd, level, optname,
optval, optlen);
if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
return do_set_sock_timeout(fd, level, optname, optval, optlen);
if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
return do_set_icmpv6_filter(fd, level, optname,
optval, optlen);
......@@ -588,6 +614,39 @@ asmlinkage int sys32_setsockopt(int fd, int level, int optname,
return sys_setsockopt(fd, level, optname, optval, optlen);
}
static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int *optlen)
{
struct compat_timeval *up = (struct compat_timeval *) optval;
struct timeval ktime;
mm_segment_t old_fs;
int len, err;
if (get_user(len, optlen))
return -EFAULT;
if (len < sizeof(*up))
return -EINVAL;
len = sizeof(ktime);
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len);
set_fs(old_fs);
if (!err) {
if (put_user(sizeof(*up), optlen) ||
put_user(ktime.tv_sec, &up->tv_sec) ||
__put_user(ktime.tv_usec, &up->tv_usec))
err = -EFAULT;
}
return err;
}
asmlinkage long sys32_getsockopt(int fd, int level, int optname,
char *optval, int *optlen)
{
if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
return do_get_sock_timeout(fd, level, optname, optval, optlen);
return sys_getsockopt(fd, level, optname, optval, optlen);
}
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
......@@ -606,14 +665,11 @@ extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr,
extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr,
int *usockaddr_len);
extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags);
extern asmlinkage long sys_sendto(int fd, u32 buff, __kernel_size_t32 len,
extern asmlinkage long sys_sendto(int fd, u32 buff, compat_size_t len,
unsigned flags, u32 addr, int addr_len);
extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, compat_size_t size,
unsigned flags, u32 addr, u32 addr_len);
extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
u32 optval, u32 optlen);
extern asmlinkage long sys_socket(int family, int type, int protocol);
extern asmlinkage long sys_socketpair(int family, int type, int protocol,
int usockvec[2]);
......@@ -678,11 +734,11 @@ asmlinkage long sys32_socketcall(int call, u32 *args)
ret = sys_shutdown(a0,a1);
break;
case SYS_SETSOCKOPT:
ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]),
ret = sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]),
a[4]);
break;
case SYS_GETSOCKOPT:
ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]);
ret = sys32_getsockopt(a0, a1, a[2], (char *)(u64)a[3], (int *)(u64)a[4]);
break;
case SYS_SENDMSG:
ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1),
......
......@@ -26,7 +26,6 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/signal.h>
#include <linux/utime.h>
#include <linux/resource.h>
#include <linux/times.h>
#include <linux/utsname.h>
......@@ -58,6 +57,7 @@
#include <linux/binfmts.h>
#include <linux/init.h>
#include <linux/aio_abi.h>
#include <linux/compat.h>
#include <asm/mman.h>
#include <asm/types.h>
#include <asm/uaccess.h>
......@@ -86,78 +86,29 @@
extern int overflowuid,overflowgid;
static int
putstat(struct stat32 *ubuf, struct stat *kbuf)
{
if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat32)) ||
__put_user (kbuf->st_dev, &ubuf->st_dev) ||
__put_user (kbuf->st_ino, &ubuf->st_ino) ||
__put_user (kbuf->st_mode, &ubuf->st_mode) ||
__put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
__put_user (kbuf->st_uid, &ubuf->st_uid) ||
__put_user (kbuf->st_gid, &ubuf->st_gid) ||
__put_user (kbuf->st_rdev, &ubuf->st_rdev) ||
__put_user (kbuf->st_size, &ubuf->st_size) ||
__put_user (kbuf->st_atime, &ubuf->st_atime) ||
__put_user (kbuf->st_mtime, &ubuf->st_mtime) ||
__put_user (kbuf->st_ctime, &ubuf->st_ctime) ||
__put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
__put_user (kbuf->st_blocks, &ubuf->st_blocks))
int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf)
{
if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
__put_user (kbuf->dev, &ubuf->st_dev) ||
__put_user (kbuf->ino, &ubuf->st_ino) ||
__put_user (kbuf->mode, &ubuf->st_mode) ||
__put_user (kbuf->nlink, &ubuf->st_nlink) ||
__put_user (kbuf->uid, &ubuf->st_uid) ||
__put_user (kbuf->gid, &ubuf->st_gid) ||
__put_user (kbuf->rdev, &ubuf->st_rdev) ||
__put_user (kbuf->size, &ubuf->st_size) ||
__put_user (kbuf->atime.tv_sec, &ubuf->st_atime) ||
__put_user (kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
__put_user (kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
__put_user (kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
__put_user (kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
__put_user (kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
__put_user (kbuf->blksize, &ubuf->st_blksize) ||
__put_user (kbuf->blocks, &ubuf->st_blocks))
return -EFAULT;
return 0;
}
extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
asmlinkage long
sys32_newstat(char * filename, struct stat32 *statbuf)
{
int ret;
struct stat s;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_newstat(filename, &s);
set_fs (old_fs);
if (putstat (statbuf, &s))
return -EFAULT;
return ret;
}
extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
asmlinkage long
sys32_newlstat(char * filename, struct stat32 *statbuf)
{
int ret;
struct stat s;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_newlstat(filename, &s);
set_fs (old_fs);
if (putstat (statbuf, &s))
return -EFAULT;
return ret;
}
extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
asmlinkage long
sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
{
int ret;
struct stat s;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_newfstat(fd, &s);
set_fs (old_fs);
if (putstat (statbuf, &s))
return -EFAULT;
return ret;
}
/* Another set for IA32/LFS -- x86_64 struct stat is different due to
support for 64bit inode numbers. */
......@@ -175,8 +126,11 @@ putstat64(struct stat64 *ubuf, struct stat *kbuf)
__put_user (kbuf->st_rdev, &ubuf->st_rdev) ||
__put_user (kbuf->st_size, &ubuf->st_size) ||
__put_user (kbuf->st_atime, &ubuf->st_atime) ||
__put_user (kbuf->st_atime_nsec, &ubuf->st_atime_nsec) ||
__put_user (kbuf->st_mtime, &ubuf->st_mtime) ||
__put_user (kbuf->st_mtime_nsec, &ubuf->st_mtime_nsec) ||
__put_user (kbuf->st_ctime, &ubuf->st_ctime) ||
__put_user (kbuf->st_ctime_nsec, &ubuf->st_ctime_nsec) ||
__put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
__put_user (kbuf->st_blocks, &ubuf->st_blocks))
return -EFAULT;
......@@ -245,7 +199,7 @@ struct mmap_arg_struct {
unsigned int offset;
};
asmlinkage __u32
asmlinkage long
sys32_mmap(struct mmap_arg_struct *arg)
{
struct mmap_arg_struct a;
......@@ -265,10 +219,8 @@ sys32_mmap(struct mmap_arg_struct *arg)
return -EBADF;
}
#if 0 /* reenable when noexec works */
if (a.prot & PROT_READ)
a.prot |= PROT_EXEC;
#endif
a.flags |= MAP_32BIT;
......@@ -279,7 +231,7 @@ sys32_mmap(struct mmap_arg_struct *arg)
fput(file);
/* Cannot wrap */
if (retval+a.len >= 0xFFFFFFFF && (long)retval > 0) {
if (retval+a.len >= IA32_PAGE_OFFSET && (long)retval > 0) {
do_munmap(mm, retval, a.len);
retval = -ENOMEM;
}
......@@ -290,7 +242,8 @@ sys32_mmap(struct mmap_arg_struct *arg)
extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
asmlinkage int sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
asmlinkage long
sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
{
if (prot & PROT_READ)
prot |= PROT_EXEC;
......@@ -498,19 +451,8 @@ sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
return ret;
}
struct timeval32
{
int tv_sec, tv_usec;
};
struct itimerval32
{
struct timeval32 it_interval;
struct timeval32 it_value;
};
static inline long
get_tv32(struct timeval *o, struct timeval32 *i)
get_tv32(struct timeval *o, struct compat_timeval *i)
{
int err = -EFAULT;
if (access_ok(VERIFY_READ, i, sizeof(*i))) {
......@@ -521,7 +463,7 @@ get_tv32(struct timeval *o, struct timeval32 *i)
}
static inline long
put_tv32(struct timeval32 *o, struct timeval *i)
put_tv32(struct compat_timeval *o, struct timeval *i)
{
int err = -EFAULT;
if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
......@@ -531,71 +473,7 @@ put_tv32(struct timeval32 *o, struct timeval *i)
return err;
}
static inline long
get_it32(struct itimerval *o, struct itimerval32 *i)
{
int err = -EFAULT;
if (access_ok(VERIFY_READ, i, sizeof(*i))) {
err = __get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec);
err |= __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec);
err |= __get_user(o->it_value.tv_sec, &i->it_value.tv_sec);
err |= __get_user(o->it_value.tv_usec, &i->it_value.tv_usec);
}
return err;
}
static inline long
put_it32(struct itimerval32 *o, struct itimerval *i)
{
int err = -EFAULT;
if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
err = __put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec);
err |= __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec);
err |= __put_user(i->it_value.tv_sec, &o->it_value.tv_sec);
err |= __put_user(i->it_value.tv_usec, &o->it_value.tv_usec);
}
return err;
}
extern int do_getitimer(int which, struct itimerval *value);
asmlinkage long
sys32_getitimer(int which, struct itimerval32 *it)
{
struct itimerval kit;
int error;
error = do_getitimer(which, &kit);
if (!error && put_it32(it, &kit))
error = -EFAULT;
return error;
}
extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
asmlinkage long
sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
{
struct itimerval kin, kout;
int error;
if (in) {
if (get_it32(&kin, in))
return -EFAULT;
} else
memset(&kin, 0, sizeof(kin));
error = do_setitimer(which, &kin, out ? &kout : NULL);
if (error || !out)
return error;
if (put_it32(out, &kout))
return -EFAULT;
return 0;
}
asmlinkage unsigned long
sys32_alarm(unsigned int seconds)
{
struct itimerval it_new, it_old;
......@@ -616,45 +494,11 @@ sys32_alarm(unsigned int seconds)
/* Translations due to time_t size differences. Which affects all
sorts of things, like timeval and itimerval. */
struct utimbuf_32 {
int atime;
int mtime;
};
extern asmlinkage long sys_utimes(char * filename, struct timeval * utimes);
extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz);
asmlinkage long
ia32_utime(char * filename, struct utimbuf_32 *times32)
{
mm_segment_t old_fs = get_fs();
struct timeval tv[2];
long ret;
if (times32) {
get_user(tv[0].tv_sec, &times32->atime);
tv[0].tv_usec = 0;
get_user(tv[1].tv_sec, &times32->mtime);
tv[1].tv_usec = 0;
set_fs (KERNEL_DS);
} else {
set_fs (KERNEL_DS);
ret = sys_gettimeofday(&tv[0], 0);
if (ret < 0)
goto out;
tv[1] = tv[0];
}
ret = sys_utimes(filename, tv);
out:
set_fs (old_fs);
return ret;
}
extern struct timezone sys_tz;
extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
asmlinkage long
sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
{
if (tv) {
struct timeval ktv;
......@@ -670,7 +514,7 @@ sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
}
asmlinkage long
sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
{
struct timeval ktv;
struct timezone ktz;
......@@ -827,7 +671,7 @@ sys32_oldreaddir (unsigned int fd, void * dirent, unsigned int count)
#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))
asmlinkage long
sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32)
sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct compat_timeval *tvp32)
{
fd_set_bits fds;
char *bits;
......@@ -931,37 +775,7 @@ sys32_old_select(struct sel_arg_struct *arg)
if (copy_from_user(&a, arg, sizeof(a)))
return -EFAULT;
return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp),
(struct timeval32 *)A(a.tvp));
}
struct timespec32 {
int tv_sec;
int tv_nsec;
};
extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
asmlinkage long
sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
{
struct timespec t;
int ret;
mm_segment_t old_fs = get_fs ();
if (verify_area(VERIFY_READ, rqtp, sizeof(struct timespec32)) ||
__get_user (t.tv_sec, &rqtp->tv_sec) ||
__get_user (t.tv_nsec, &rqtp->tv_nsec))
return -EFAULT;
set_fs (KERNEL_DS);
ret = sys_nanosleep(&t, rmtp ? &t : NULL);
set_fs (old_fs);
if (rmtp && ret == -EINTR) {
if (verify_area(VERIFY_WRITE, rmtp, sizeof(struct timespec32)) ||
__put_user (t.tv_sec, &rmtp->tv_sec) ||
__put_user (t.tv_nsec, &rmtp->tv_nsec))
return -EFAULT;
}
return ret;
(struct compat_timeval *)A(a.tvp));
}
asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
......@@ -1153,8 +967,8 @@ asmlinkage long sys32_time(int * tloc)
}
struct rusage32 {
struct timeval32 ru_utime;
struct timeval32 ru_stime;
struct compat_timeval ru_utime;
struct compat_timeval ru_stime;
int ru_maxrss;
int ru_ixrss;
int ru_idrss;
......@@ -1201,7 +1015,7 @@ extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr,
int options, struct rusage * ru);
asmlinkage long
sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
sys32_wait4(compat_pid_t pid, unsigned int *stat_addr, int options,
struct rusage32 *ru)
{
if (!ru)
......@@ -1223,7 +1037,7 @@ sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
}
asmlinkage long
sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options)
sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
{
return sys32_wait4(pid, stat_addr, options, NULL);
}
......@@ -1246,37 +1060,6 @@ sys32_getrusage(int who, struct rusage32 *ru)
return ret;
}
struct tms32 {
__kernel_clock_t32 tms_utime;
__kernel_clock_t32 tms_stime;
__kernel_clock_t32 tms_cutime;
__kernel_clock_t32 tms_cstime;
};
extern int sys_times(struct tms *);
asmlinkage long
sys32_times(struct tms32 *tbuf)
{
struct tms t;
long ret;
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_times(tbuf ? &t : NULL);
set_fs (old_fs);
if (tbuf) {
if (verify_area(VERIFY_WRITE, tbuf, sizeof(struct tms32)) ||
__put_user (t.tms_utime, &tbuf->tms_utime) ||
__put_user (t.tms_stime, &tbuf->tms_stime) ||
__put_user (t.tms_cutime, &tbuf->tms_cutime) ||
__put_user (t.tms_cstime, &tbuf->tms_cstime))
return -EFAULT;
}
return ret;
}
static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
{
int err;
......@@ -1406,38 +1189,6 @@ int sys32_ni_syscall(int call)
/* 32-bit timeval and related flotsam. */
extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
struct utimbuf32 {
__kernel_time_t32 actime, modtime;
};
asmlinkage long
sys32_utime(char * filename, struct utimbuf32 *times)
{
struct utimbuf t;
mm_segment_t old_fs;
int ret;
char *filenam;
if (!times)
return sys_utime(filename, NULL);
if (verify_area(VERIFY_READ, times, sizeof(struct utimbuf32)) ||
__get_user (t.actime, &times->actime) ||
__get_user (t.modtime, &times->modtime))
return -EFAULT;
filenam = getname (filename);
ret = PTR_ERR(filenam);
if (!IS_ERR(filenam)) {
old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_utime(filenam, &t);
set_fs (old_fs);
putname(filenam);
}
return ret;
}
extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
unsigned long arg2);
......@@ -1528,7 +1279,7 @@ extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
struct timespec *interval);
asmlinkage long
sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec *interval)
{
struct timespec t;
int ret;
......@@ -1537,7 +1288,7 @@ sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
set_fs (KERNEL_DS);
ret = sys_sched_rr_get_interval(pid, &t);
set_fs (old_fs);
if (verify_area(VERIFY_WRITE, interval, sizeof(struct timespec32)) ||
if (verify_area(VERIFY_WRITE, interval, sizeof(struct compat_timespec)) ||
__put_user (t.tv_sec, &interval->tv_sec) ||
__put_user (t.tv_nsec, &interval->tv_nsec))
return -EFAULT;
......@@ -1582,7 +1333,7 @@ sys32_sigpending(old_sigset32_t *set)
extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
asmlinkage long
sys32_rt_sigpending(sigset32_t *set, __kernel_size_t32 sigsetsize)
sys32_rt_sigpending(sigset32_t *set, compat_size_t sigsetsize)
{
sigset_t s;
sigset32_t s32;
......@@ -1688,7 +1439,7 @@ sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
asmlinkage long
sys32_rt_sigtimedwait(sigset32_t *uthese, siginfo_t32 *uinfo,
struct timespec32 *uts, __kernel_size_t32 sigsetsize)
struct compat_timespec *uts, compat_size_t sigsetsize)
{
sigset_t s;
sigset32_t s32;
......@@ -1707,7 +1458,7 @@ sys32_rt_sigtimedwait(sigset32_t *uthese, siginfo_t32 *uinfo,
case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
}
if (uts) {
if (verify_area(VERIFY_READ, uts, sizeof(struct timespec32)) ||
if (verify_area(VERIFY_READ, uts, sizeof(struct compat_timespec)) ||
__get_user (t.tv_sec, &uts->tv_sec) ||
__get_user (t.tv_nsec, &uts->tv_nsec))
return -EFAULT;
......@@ -1749,7 +1500,7 @@ extern void check_pending(int signum);
asmlinkage long sys_utimes(char *, struct timeval *);
asmlinkage long
sys32_utimes(char *filename, struct timeval32 *tvs)
sys32_utimes(char *filename, struct compat_timeval *tvs)
{
char *kfilename;
struct timeval ktvs[2];
......@@ -1851,21 +1602,16 @@ extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
size_t count, loff_t pos);
typedef __kernel_ssize_t32 ssize_t32;
/* warning: next two assume little endian */
asmlinkage ssize_t32
sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
u32 poslo, u32 poshi)
asmlinkage long
sys32_pread(unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi)
{
return sys_pread64(fd, ubuf, count,
((loff_t)AA(poshi) << 32) | AA(poslo));
}
asmlinkage ssize_t32
sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
u32 poslo, u32 poshi)
asmlinkage long
sys32_pwrite(unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi)
{
return sys_pwrite64(fd, ubuf, count,
((loff_t)AA(poshi) << 32) | AA(poslo));
......@@ -1891,7 +1637,7 @@ extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset,
size_t count);
asmlinkage long
sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
......@@ -1916,7 +1662,7 @@ struct timex32 {
u32 modes;
s32 offset, freq, maxerror, esterror;
s32 status, constant, precision, tolerance;
struct timeval32 time;
struct compat_timeval time;
s32 tick;
s32 ppsfreq, jitter, shift, stabil;
s32 jitcnt, calcnt, errcnt, stbcnt;
......@@ -2001,14 +1747,15 @@ asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
return -EBADF;
}
/* later add PROT_EXEC for PROT_READ here */
if (prot & PROT_READ)
prot |= PROT_EXEC;
down_write(&mm->mmap_sem);
error = do_mmap_pgoff(file, addr, len, prot, flags|MAP_32BIT, pgoff);
up_write(&mm->mmap_sem);
/* cannot wrap */
if (error+len >= 0xFFFFFFFF && (long)error >= 0) {
if (error+len >= IA32_PAGE_OFFSET && (long)error >= 0) {
do_munmap(mm, error, len);
error = -ENOMEM;
}
......@@ -2051,7 +1798,7 @@ asmlinkage long sys32_olduname(struct oldold_utsname * name)
return error;
}
int sys32_uname(struct old_utsname * name)
long sys32_uname(struct old_utsname * name)
{
int err;
if (!name)
......@@ -2066,7 +1813,7 @@ int sys32_uname(struct old_utsname * name)
extern int sys_ustat(dev_t, struct ustat *);
int sys32_ustat(dev_t dev, struct ustat32 *u32p)
long sys32_ustat(dev_t dev, struct ustat32 *u32p)
{
struct ustat u;
mm_segment_t seg;
......@@ -2109,7 +1856,7 @@ static int nargs(u32 src, char **dst)
return cnt;
}
int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
{
mm_segment_t oldseg;
char **buf;
......@@ -2163,20 +1910,22 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
return ret;
}
asmlinkage int sys32_fork(struct pt_regs regs)
asmlinkage long sys32_fork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL);
p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
{
struct task_struct *p;
int *user_tid = (int *)regs.rdx;
void *parent_tid = (void *)regs.rdx;
void *child_tid = (void *)regs.rdi;
if (!newsp)
newsp = regs.rsp;
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
parent_tid, child_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -2190,10 +1939,10 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
asmlinkage int sys32_vfork(struct pt_regs regs)
asmlinkage long sys32_vfork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL);
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -2203,14 +1952,14 @@ asmlinkage int sys32_vfork(struct pt_regs regs)
extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
int sys32_lseek (unsigned int fd, int offset, unsigned int whence)
long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
{
return sys_lseek(fd, offset, whence);
}
extern int sys_kill(pid_t pid, int sig);
int sys32_kill(int pid, int sig)
long sys32_kill(int pid, int sig)
{
return sys_kill(pid, sig);
}
......@@ -2235,27 +1984,27 @@ struct nfsctl_client32 {
struct nfsctl_export32 {
s8 ex32_client[NFSCLNT_IDMAX+1];
s8 ex32_path[NFS_MAXPATHLEN+1];
__kernel_dev_t32 ex32_dev;
__kernel_ino_t32 ex32_ino;
compat_dev_t ex32_dev;
compat_ino_t ex32_ino;
s32 ex32_flags;
__kernel_uid_t32 ex32_anon_uid;
__kernel_gid_t32 ex32_anon_gid;
compat_pid_t ex32_anon_uid;
compat_gid_t ex32_anon_gid;
};
struct nfsctl_uidmap32 {
u32 ug32_ident; /* char * */
__kernel_uid_t32 ug32_uidbase;
compat_pid_t ug32_uidbase;
s32 ug32_uidlen;
u32 ug32_udimap; /* uid_t * */
__kernel_uid_t32 ug32_gidbase;
compat_pid_t ug32_gidbase;
s32 ug32_gidlen;
u32 ug32_gdimap; /* gid_t * */
};
struct nfsctl_fhparm32 {
struct sockaddr gf32_addr;
__kernel_dev_t32 gf32_dev;
__kernel_ino_t32 gf32_ino;
compat_dev_t gf32_dev;
compat_ino_t gf32_ino;
s32 gf32_version;
};
......@@ -2384,7 +2133,7 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
return -ENOMEM;
for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
err |= __get_user(karg->ca_umap.ug_udimap[i],
&(((__kernel_uid_t32 *)A(uaddr))[i]));
&(((compat_pid_t *)A(uaddr))[i]));
err |= __get_user(karg->ca_umap.ug_gidbase,
&arg32->ca32_umap.ug32_gidbase);
err |= __get_user(karg->ca_umap.ug_uidlen,
......@@ -2398,7 +2147,7 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
return -ENOMEM;
for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
err |= __get_user(karg->ca_umap.ug_gdimap[i],
&(((__kernel_gid_t32 *)A(uaddr))[i]));
&(((compat_gid_t *)A(uaddr))[i]));
return err;
}
......@@ -2460,7 +2209,7 @@ static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res
return copy_to_user(res32, kres, sizeof(*res32));
}
int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
{
struct nfsctl_arg *karg = NULL;
union nfsctl_res *kres = NULL;
......@@ -2541,13 +2290,13 @@ int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsct
}
#else /* !NFSD */
extern asmlinkage long sys_ni_syscall(void);
int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
{
return sys_ni_syscall();
}
#endif
int sys32_module_warning(void)
long sys32_module_warning(void)
{
static long warn_time = -(60*HZ);
if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) {
......@@ -2562,7 +2311,7 @@ int sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long *new_mask_p
int sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long *new_mask_ptr);
/* only works on LE */
int sys32_sched_setaffinity(pid_t pid, unsigned int len,
long sys32_sched_setaffinity(pid_t pid, unsigned int len,
unsigned int *new_mask_ptr)
{
mm_segment_t oldfs = get_fs();
......@@ -2577,7 +2326,7 @@ int sys32_sched_setaffinity(pid_t pid, unsigned int len,
}
/* only works on LE */
int sys32_sched_getaffinity(pid_t pid, unsigned int len,
long sys32_sched_getaffinity(pid_t pid, unsigned int len,
unsigned int *new_mask_ptr)
{
mm_segment_t oldfs = get_fs();
......@@ -2587,11 +2336,38 @@ int sys32_sched_getaffinity(pid_t pid, unsigned int len,
set_fs(KERNEL_DS);
err = sys_sched_getaffinity(pid,sizeof(mask),&mask);
set_fs(oldfs);
if (!err)
if (err > 0)
err = put_user((u32)mask, new_mask_ptr);
return err;
}
extern int sys_futex(unsigned long uaddr, int op, int val, struct timespec *t);
asmlinkage long
sys32_futex(unsigned long uaddr, int op, int val, struct compat_timespec *utime32)
{
struct timespec t;
mm_segment_t oldfs = get_fs();
int err;
if (utime32) {
if (verify_area(VERIFY_READ, utime32, sizeof(*utime32)))
return -EFAULT;
if (__get_user(t.tv_sec, &utime32->tv_sec) ||
__get_user(t.tv_nsec, &utime32->tv_nsec))
return -EFAULT;
}
/* the set_fs is safe because futex doesn't use the seg limit
for valid page checking of uaddr. */
set_fs(KERNEL_DS);
err = sys_futex(uaddr, op, val, &t);
set_fs(oldfs);
return err;
}
extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
......@@ -2608,8 +2384,53 @@ long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
return ret;
}
extern asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr,
struct iocb **iocbpp);
long sys32_io_submit(aio_context_t ctx_id, unsigned long nr,
u32 *iocbpp)
{
mm_segment_t oldfs = get_fs();
int k, err = 0;
struct iocb **iocb64;
if (nr > 128)
return -EINVAL;
iocb64 = kmalloc(sizeof(struct iocb *) * nr, GFP_KERNEL);
if (!iocb64)
return -ENOMEM;
for (k = 0; k < nr && !err; k++) {
u64 val1, val2;
u32 iocb32;
struct iocb *iocb;
err = get_user(iocb32, (u32 *)(u64)iocbpp[k]);
iocb64[k] = iocb = (void *)(u64)iocb32;
if (get_user(val1, &iocb->aio_buf) ||
get_user(val2, &iocb->aio_nbytes))
err = -EFAULT;
else if (!val1) /* should check cmd */
;
else if (verify_area(VERIFY_WRITE, (void*)val1, val2))
err = -EFAULT;
/* paranoia check - remove it when you are sure they
are not pointers */
if (get_user(val1, &iocb->aio_reserved2) || val1 ||
get_user(val2, &iocb->aio_reserved2) || val2)
err = -EFAULT;
}
if (!err) {
set_fs(KERNEL_DS);
err = sys_io_submit(ctx_id, nr, iocb64);
set_fs(oldfs);
}
kfree(iocb64);
return err;
}
/* XXX aio getevents */
int sys32_vm86_warning(void)
long sys32_vm86_warning(void)
{
static long warn_time = -(60*HZ);
if (time_before(warn_time + 60*HZ,jiffies)) {
......
......@@ -4,23 +4,30 @@
EXTRA_TARGETS := head.o head64.o init_task.o
export-objs := mtrr.o x8664_ksyms.o pci-gart.o pci-dma.o
export-objs := x8664_ksyms.o pci-gart.o pci-dma.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \
setup64.o bluesmoke.o bootflag.o e820.o reboot.o profile.o
obj-$(CONFIG_MTRR) += mtrr.o
obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o suspend_asm.o
obj-$(CONFIG_ACPI) += acpi.o
#obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o
obj-$(CONFIG_MODULES) += module.o
$(obj)/bootflag.c:
@ln -sf ../../i386/kernel/bootflag.c $(obj)/bootflag.c
clean-files += bootflag.c
EXTRA_AFLAGS := -traditional
......@@ -443,8 +443,6 @@ acpi_boot_init (
#error not ported to x86-64 yet
#define DEBUG
#ifdef DEBUG
#include <linux/serial.h>
#endif
......
/*
* Implement 'Simple Boot Flag Specification 1.0'
*
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/mc146818rtc.h>
#define SBF_RESERVED (0x78)
#define SBF_PNPOS (1<<0)
#define SBF_BOOTING (1<<1)
#define SBF_DIAG (1<<2)
#define SBF_PARITY (1<<7)
struct sbf_boot
{
u8 sbf_signature[4];
u32 sbf_len;
u8 sbf_revision __attribute((packed));
u8 sbf_csum __attribute((packed));
u8 sbf_oemid[6] __attribute((packed));
u8 sbf_oemtable[8] __attribute((packed));
u8 sbf_revdata[4] __attribute((packed));
u8 sbf_creator[4] __attribute((packed));
u8 sbf_crearev[4] __attribute((packed));
u8 sbf_cmos __attribute((packed));
u8 sbf_spare[3] __attribute((packed));
};
static int sbf_port __initdata = -1;
static int __init sbf_struct_valid(unsigned long tptr)
{
u8 *ap;
u8 v;
unsigned int i;
struct sbf_boot sb;
memcpy_fromio(&sb, (void *)tptr, sizeof(sb));
if(sb.sbf_len != 40 && sb.sbf_len != 39)
// 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19).
return 0;
ap = (u8 *)&sb;
v= 0;
for(i=0;i<sb.sbf_len;i++)
v+=*ap++;
if(v)
return 0;
if(memcmp(sb.sbf_signature, "BOOT", 4))
return 0;
if (sb.sbf_len == 39)
printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n",
sb.sbf_len);
sbf_port = sb.sbf_cmos; /* Save CMOS port */
return 1;
}
static int __init parity(u8 v)
{
int x = 0;
int i;
for(i=0;i<8;i++)
{
x^=(v&1);
v>>=1;
}
return x;
}
static void __init sbf_write(u8 v)
{
unsigned long flags;
if(sbf_port != -1)
{
v &= ~SBF_PARITY;
if(!parity(v))
v|=SBF_PARITY;
printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v);
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(v, sbf_port);
spin_unlock_irqrestore(&rtc_lock, flags);
}
}
static u8 __init sbf_read(void)
{
u8 v;
unsigned long flags;
if(sbf_port == -1)
return 0;
spin_lock_irqsave(&rtc_lock, flags);
v = CMOS_READ(sbf_port);
spin_unlock_irqrestore(&rtc_lock, flags);
return v;
}
static int __init sbf_value_valid(u8 v)
{
if(v&SBF_RESERVED) /* Reserved bits */
return 0;
if(!parity(v))
return 0;
return 1;
}
static void __init sbf_bootup(void)
{
u8 v;
if(sbf_port == -1)
return;
v = sbf_read();
if(!sbf_value_valid(v))
printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v);
v &= ~SBF_RESERVED;
v &= ~SBF_BOOTING;
v &= ~SBF_DIAG;
#if defined(CONFIG_ISAPNP)
v |= SBF_PNPOS;
#endif
sbf_write(v);
}
static int __init sbf_init(void)
{
unsigned int i;
void *rsdt;
u32 rsdtlen = 0;
u32 rsdtbase = 0;
u8 sum = 0;
int n;
u8 *p;
for(i=0xE0000; i <= 0xFFFE0; i+=16)
{
p = phys_to_virt(i);
if(memcmp(p, "RSD PTR ", 8))
continue;
sum = 0;
for(n=0; n<20; n++)
sum+=p[n];
if(sum != 0)
continue;
/* So it says RSD PTR and it checksums... */
/*
* Process the RDSP pointer
*/
rsdtbase = *(u32 *)(p+16);
/*
* RSDT length is ACPI 2 only, for ACPI 1 we must map
* and remap.
*/
if(p[15]>1)
rsdtlen = *(u32 *)(p+20);
else
rsdtlen = 36;
if(rsdtlen < 36 || rsdtlen > 1024)
continue;
break;
}
if(i>0xFFFE0)
return 0;
rsdt = ioremap(rsdtbase, rsdtlen);
if(rsdt == 0)
return 0;
i = readl(rsdt + 4);
/*
* Remap if needed
*/
if(i > rsdtlen)
{
rsdtlen = i;
iounmap(rsdt);
rsdt = ioremap(rsdtbase, rsdtlen);
if(rsdt == 0)
return 0;
}
for(n = 0; n < i; n++)
sum += readb(rsdt + n);
if(sum)
{
iounmap(rsdt);
return 0;
}
/* Ok the RSDT checksums too */
for(n = 36; n+3 < i; n += 4)
{
unsigned long rp = readl(rsdt+n);
int len = 4096;
if(rp > 0xFFFFFFFFUL - len)
len = 0xFFFFFFFFUL - rp;
/* Too close to the end!! */
if(len < 20)
continue;
rp = (unsigned long)ioremap(rp, 4096);
if(rp == 0)
continue;
if(sbf_struct_valid(rp))
{
/* Found the BOOT table and processed it */
printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n");
}
iounmap((void *)rp);
}
iounmap(rsdt);
sbf_bootup();
return 0;
}
module_init(sbf_init);
......@@ -605,6 +605,9 @@ ENTRY(kernel_thread)
movq $-1, %rsi
movq %rsp, %rdx
xorl %r8d,%r8d
xorl %r9d,%r9d
# clone now
call do_fork
......
......@@ -79,13 +79,11 @@ startup_32:
/* Enable System Call */
btsl $_EFER_SCE, %eax
#if 0
/* No Execute supported? */
btl $20,%edi
jnc 1f
btsl $_EFER_NX, %eax
1:
#endif
/* Make changes effective */
wrmsr
......
......@@ -127,3 +127,24 @@ int dump_fpu( struct pt_regs *regs, struct user_i387_struct *fpu )
memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct));
return 1;
}
int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu)
{
int fpvalid = tsk->used_math;
if (fpvalid) {
if (tsk == current)
unlazy_fpu(tsk);
memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct));
}
return fpvalid;
}
#ifdef CONFIG_SMP
void dump_smp_unlazy_fpu(void)
{
unlazy_fpu(current);
return;
}
#endif
......@@ -404,6 +404,45 @@ void reschedule_interrupt(void);
void call_function_interrupt(void);
void invalidate_interrupt(void);
static void setup_timer(void)
{
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
udelay(10);
outb_p(LATCH & 0xff , 0x40); /* LSB */
udelay(10);
outb(LATCH >> 8 , 0x40); /* MSB */
}
static int timer_resume(struct device *dev, u32 level)
{
if (level == RESUME_POWER_ON)
setup_timer();
return 0;
}
static struct device_driver timer_driver = {
.name = "timer",
.bus = &system_bus_type,
.resume = timer_resume,
};
static struct sys_device device_timer = {
.name = "timer",
.id = 0,
.dev = {
.name = "timer",
.driver = &timer_driver,
},
};
static int __init init_timer_devicefs(void)
{
driver_register(&timer_driver);
return sys_device_register(&device_timer);
}
device_initcall(init_timer_devicefs);
void __init init_IRQ(void)
{
int i;
......@@ -454,9 +493,7 @@ void __init init_IRQ(void)
* Set the clock to HZ Hz, we already have a valid
* vector now:
*/
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
setup_timer();
setup_irq(2, &irq2);
}
......@@ -35,6 +35,8 @@
#include <asm/smp.h>
#include <asm/desc.h>
int sis_apic_bug; /* not actually supported, dummy for compile */
#undef APIC_LOCKUP_DEBUG
#define APIC_LOCKUP_DEBUG
......
......@@ -108,13 +108,12 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
}
/*
* No need to lock the MM as we are the last user
*
* Don't touch the LDT register - we're already in the next thread.
*/
void release_segments(struct mm_struct *mm)
void destroy_context(struct mm_struct *mm)
{
if (mm->context.size) {
if (mm == current->active_mm)
clear_LDT();
if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(mm->context.ldt);
else
......@@ -188,11 +187,6 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
goto out;
}
me->thread.fsindex = 0;
me->thread.gsindex = 0;
me->thread.gs = 0;
me->thread.fs = 0;
down(&mm->context.sem);
if (ldt_info.entry_number >= mm->context.size) {
error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
......
/* Kernel module help for x86-64
Copyright (C) 2001 Rusty Russell.
Copyright (C) 2002 Andi Kleen, SuSE Labs.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#define DEBUGP(fmt...)
/* We don't need anything special. */
long module_core_size(const Elf64_Ehdr *hdr,
const Elf64_Shdr *sechdrs,
const char *secstrings,
struct module *module)
{
return module->core_size;
}
long module_init_size(const Elf64_Ehdr *hdr,
const Elf64_Shdr *sechdrs,
const char *secstrings,
struct module *module)
{
return module->init_size;
}
int apply_relocate_add(Elf64_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf64_Rela *rel = (void *)sechdrs[relsec].sh_offset;
Elf64_Sym *sym;
void *loc;
u64 val;
DEBUGP("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset
+ rel[i].r_offset;
/* This is the symbol it is referring to */
sym = (Elf64_Sym *)sechdrs[symindex].sh_offset
+ ELF64_R_SYM(rel[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
(int)ELF64_R_TYPE(rel[i].r_info),
sym->st_value, rel[i].r_addend, (u64)loc);
val = sym->st_value + rel[i].r_addend;
switch (ELF64_R_TYPE(rel[i].r_info)) {
case R_X86_64_NONE:
break;
case R_X86_64_64:
*(u64 *)loc = val;
break;
case R_X86_64_32:
*(u32 *)loc = val;
if (val != *(u32 *)loc)
goto overflow;
break;
case R_X86_64_32S:
*(s32 *)loc = val;
if ((s64)val != *(s32 *)loc)
goto overflow;
break;
case R_X86_64_PC32:
val -= (u64)loc;
*(u32 *)loc = val;
#if 0
if ((s64)val != *(s32 *)loc)
goto overflow;
#endif
break;
default:
printk(KERN_ERR "module %s: Unknown rela relocation: %Lu\n",
me->name, ELF64_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}
return 0;
overflow:
printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
(int)ELF64_R_TYPE(rel[i].r_info), val);
printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
me->name);
return -ENOEXEC;
}
int apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
printk("non add relocation not supported\n");
return -ENOSYS;
}
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
return 0;
}
/* x86-64 MTRR (Memory Type Range Register) driver.
Based largely upon arch/i386/kernel/mtrr.c
Copyright (C) 1997-2000 Richard Gooch
Copyright (C) 2002 Dave Jones.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
(For earlier history, see arch/i386/kernel/mtrr.c)
v2.00 September 2001 Dave Jones <davej@suse.de>
Initial rewrite for x86-64.
Removal of non-Intel style MTRR code.
v2.01 June 2002 Dave Jones <davej@suse.de>
Removal of redundant abstraction layer.
64-bit fixes.
v2.02 July 2002 Dave Jones <davej@suse.de>
Fix gentry inconsistencies between kernel/userspace.
More casts to clean up warnings.
Andi Kleen - rework initialization.
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/proc_fs.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#define MTRR_NEED_STRINGS
#include <asm/mtrr.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/agp_backend.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
#include <asm/msr.h>
#include <asm/hardirq.h>
#include <linux/irq.h>
#define MTRR_VERSION "2.02 (20020716)"
#define TRUE 1
#define FALSE 0
#define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
#define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
#define NUM_FIXED_RANGES 88
#define MTRR_CHANGE_MASK_FIXED 0x01
#define MTRR_CHANGE_MASK_VARIABLE 0x02
#define MTRR_CHANGE_MASK_DEFTYPE 0x04
typedef u8 mtrr_type;
#define LINE_SIZE 80
#ifdef CONFIG_SMP
#define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
#else
#define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type, TRUE)
#endif
#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)
#define USERSPACE_INTERFACE
#endif
#ifdef USERSPACE_INTERFACE
static char *ascii_buffer;
static unsigned int ascii_buf_bytes;
static void compute_ascii (void);
#else
#define compute_ascii() while (0)
#endif
static unsigned int *usage_table;
static DECLARE_MUTEX (mtrr_lock);
struct set_mtrr_context {
u32 deftype_lo;
u32 deftype_hi;
unsigned long flags;
u64 cr4val;
};
/* Put the processor into a state where MTRRs can be safely set */
static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
{
u64 cr0;
/* Disable interrupts locally */
local_irq_save(ctxt->flags);
local_irq_disable();
/* Save value of CR4 and clear Page Global Enable (bit 7) */
if (cpu_has_pge) {
ctxt->cr4val = read_cr4();
write_cr4(ctxt->cr4val & ~(1UL << 7));
}
/* Disable and flush caches. Note that wbinvd flushes the TLBs as
a side-effect */
cr0 = read_cr0() | 0x40000000;
wbinvd();
write_cr0(cr0);
wbinvd();
/* Disable MTRRs, and set the default type to uncached */
rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
}
/* Restore the processor after a set_mtrr_prepare */
static void set_mtrr_done (struct set_mtrr_context *ctxt)
{
/* Flush caches and TLBs */
wbinvd();
/* Restore MTRRdefType */
wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
/* Enable caches */
write_cr0(read_cr0() & 0xbfffffff);
/* Restore value of CR4 */
if (cpu_has_pge)
write_cr4 (ctxt->cr4val);
/* Re-enable interrupts locally (if enabled previously) */
local_irq_restore(ctxt->flags);
}
/* This function returns the number of variable MTRRs */
static unsigned int get_num_var_ranges (void)
{
u32 config, dummy;
rdmsr (MSR_MTRRcap, config, dummy);
return (config & 0xff);
}
/* Returns non-zero if we have the write-combining memory type */
static int have_wrcomb (void)
{
u32 config, dummy;
rdmsr (MSR_MTRRcap, config, dummy);
return (config & (1 << 10));
}
static u64 size_or_mask, size_and_mask;
static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type)
{
u32 mask_lo, mask_hi, base_lo, base_hi;
u64 newsize;
rdmsr (MSR_MTRRphysMask(reg), mask_lo, mask_hi);
if ((mask_lo & 0x800) == 0) {
/* Invalid (i.e. free) range */
*base = 0;
*size = 0;
*type = 0;
return;
}
rdmsr (MSR_MTRRphysBase(reg), base_lo, base_hi);
/* Work out the shifted address mask. */
newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800);
newsize = ~newsize+1;
*size = (u32) newsize >> PAGE_SHIFT;
*base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
*type = base_lo & 0xff;
}
/*
* Set variable MTRR register on the local CPU.
* <reg> The register to set.
* <base> The base address of the region.
* <size> The size of the region. If this is 0 the region is disabled.
* <type> The type of the region.
* <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
* be done externally.
*/
static void set_mtrr_up (unsigned int reg, u64 base,
u32 size, mtrr_type type, int do_safe)
{
struct set_mtrr_context ctxt;
u64 base64;
u64 size64;
if (do_safe)
set_mtrr_prepare (&ctxt);
if (size == 0) {
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
wrmsr (MSR_MTRRphysMask(reg), 0, 0);
} else {
base64 = (base << PAGE_SHIFT) & size_and_mask;
wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32);
size64 = ~((size << PAGE_SHIFT) - 1);
size64 = size64 & size_and_mask;
wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32));
}
if (do_safe)
set_mtrr_done (&ctxt);
}
#ifdef CONFIG_SMP
struct mtrr_var_range {
u32 base_lo;
u32 base_hi;
u32 mask_lo;
u32 mask_hi;
};
/* Get the MSR pair relating to a var range */
static void __init get_mtrr_var_range (unsigned int index,
struct mtrr_var_range *vr)
{
rdmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);
rdmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);
}
/* Set the MSR pair relating to a var range. Returns TRUE if
changes are made */
static int __init set_mtrr_var_range_testing (unsigned int index,
struct mtrr_var_range *vr)
{
u32 lo, hi;
int changed = FALSE;
rdmsr (MSR_MTRRphysBase(index), lo, hi);
if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) ||
(vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) {
wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);
changed = TRUE;
}
rdmsr (MSR_MTRRphysMask(index), lo, hi);
if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) ||
(vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) {
wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);
changed = TRUE;
}
return changed;
}
static void __init get_fixed_ranges (mtrr_type * frs)
{
u32 *p = (u32 *) frs;
int i;
rdmsr (MSR_MTRRfix64K_00000, p[0], p[1]);
for (i = 0; i < 2; i++)
rdmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
for (i = 0; i < 8; i++)
rdmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
}
static int __init set_fixed_ranges_testing (mtrr_type * frs)
{
u32 *p = (u32 *) frs;
int changed = FALSE;
int i;
u32 lo, hi;
printk (KERN_INFO "mtrr: rdmsr 64K_00000\n");
rdmsr (MSR_MTRRfix64K_00000, lo, hi);
if (p[0] != lo || p[1] != hi) {
printk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi);
wrmsr (MSR_MTRRfix64K_00000, p[0], p[1]);
changed = TRUE;
}
printk (KERN_INFO "mtrr: rdmsr 16K_80000\n");
for (i = 0; i < 2; i++) {
rdmsr (MSR_MTRRfix16K_80000 + i, lo, hi);
if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
printk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi );
wrmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
changed = TRUE;
}
}
printk (KERN_INFO "mtrr: rdmsr 4K_C0000\n");
for (i = 0; i < 8; i++) {
rdmsr (MSR_MTRRfix4K_C0000 + i, lo, hi);
printk (KERN_INFO "mtrr: MTRRfix4K_C0000+%d = %x:%x\n", i, lo, hi);
if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
printk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi);
wrmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
changed = TRUE;
}
}
return changed;
}
struct mtrr_state {
unsigned int num_var_ranges;
struct mtrr_var_range *var_ranges;
mtrr_type fixed_ranges[NUM_FIXED_RANGES];
mtrr_type def_type;
unsigned char enabled;
};
/* Grab all of the MTRR state for this CPU into *state */
static void __init get_mtrr_state (struct mtrr_state *state)
{
unsigned int nvrs, i;
struct mtrr_var_range *vrs;
u32 lo, dummy;
nvrs = state->num_var_ranges = get_num_var_ranges();
vrs = state->var_ranges
= kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
if (vrs == NULL)
nvrs = state->num_var_ranges = 0;
for (i = 0; i < nvrs; i++)
get_mtrr_var_range (i, &vrs[i]);
get_fixed_ranges (state->fixed_ranges);
rdmsr (MSR_MTRRdefType, lo, dummy);
state->def_type = (lo & 0xff);
state->enabled = (lo & 0xc00) >> 10;
}
/* Free resources associated with a struct mtrr_state */
static void __init finalize_mtrr_state (struct mtrr_state *state)
{
if (state->var_ranges)
kfree (state->var_ranges);
}
/*
* Set the MTRR state for this CPU.
* <state> The MTRR state information to read.
* <ctxt> Some relevant CPU context.
* [NOTE] The CPU must already be in a safe state for MTRR changes.
* [RETURNS] 0 if no changes made, else a mask indication what was changed.
*/
static u64 __init set_mtrr_state (struct mtrr_state *state,
struct set_mtrr_context *ctxt)
{
unsigned int i;
u64 change_mask = 0;
for (i = 0; i < state->num_var_ranges; i++)
if (set_mtrr_var_range_testing (i, &state->var_ranges[i]))
change_mask |= MTRR_CHANGE_MASK_VARIABLE;
if (set_fixed_ranges_testing (state->fixed_ranges))
change_mask |= MTRR_CHANGE_MASK_FIXED;
/* Set_mtrr_restore restores the old value of MTRRdefType,
so to set it we fiddle with the saved value */
if ((ctxt->deftype_lo & 0xff) != state->def_type
|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) {
ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
}
return change_mask;
}
static atomic_t undone_count;
static volatile int wait_barrier_execute = FALSE;
static volatile int wait_barrier_cache_enable = FALSE;
struct set_mtrr_data {
u64 smp_base;
u32 smp_size;
unsigned int smp_reg;
mtrr_type smp_type;
};
/*
* Synchronisation handler. Executed by "other" CPUs.
*/
static void ipi_handler (void *info)
{
struct set_mtrr_data *data = info;
struct set_mtrr_context ctxt;
set_mtrr_prepare (&ctxt);
/* Notify master that I've flushed and disabled my cache */
atomic_dec (&undone_count);
while (wait_barrier_execute)
barrier ();
/* The master has cleared me to execute */
set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size,
data->smp_type, FALSE);
/* Notify master CPU that I've executed the function */
atomic_dec (&undone_count);
/* Wait for master to clear me to enable cache and return */
while (wait_barrier_cache_enable)
barrier ();
set_mtrr_done (&ctxt);
}
static void set_mtrr_smp (unsigned int reg, u64 base, u32 size, mtrr_type type)
{
struct set_mtrr_data data;
struct set_mtrr_context ctxt;
data.smp_reg = reg;
data.smp_base = base;
data.smp_size = size;
data.smp_type = type;
wait_barrier_execute = TRUE;
wait_barrier_cache_enable = TRUE;
atomic_set (&undone_count, num_online_cpus() - 1);
/* Start the ball rolling on other CPUs */
if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
panic ("mtrr: timed out waiting for other CPUs\n");
/* Flush and disable the local CPU's cache */
set_mtrr_prepare (&ctxt);
/* Wait for all other CPUs to flush and disable their caches */
while (atomic_read (&undone_count) > 0)
barrier ();
/* Set up for completion wait and then release other CPUs to change MTRRs */
atomic_set (&undone_count, num_online_cpus() - 1);
wait_barrier_execute = FALSE;
set_mtrr_up (reg, base, size, type, FALSE);
/* Now wait for other CPUs to complete the function */
while (atomic_read (&undone_count) > 0)
barrier ();
/* Now all CPUs should have finished the function. Release the barrier to
allow them to re-enable their caches and return from their interrupt,
then enable the local cache and return */
wait_barrier_cache_enable = FALSE;
set_mtrr_done (&ctxt);
}
/* Some BIOS's are fucked and don't set all MTRRs the same! */
static void __init mtrr_state_warn (u32 mask)
{
if (!mask)
return;
if (mask & MTRR_CHANGE_MASK_FIXED)
printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
if (mask & MTRR_CHANGE_MASK_VARIABLE)
printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
if (mask & MTRR_CHANGE_MASK_DEFTYPE)
printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
printk ("mtrr: probably your BIOS does not setup all CPUs\n");
}
#endif /* CONFIG_SMP */
static inline char * attrib_to_str (int x)
{
return (x <= 6) ? mtrr_strings[x] : "?";
}
static void __init init_table (void)
{
int i, max;
max = get_num_var_ranges ();
if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) {
printk ("mtrr: could not allocate\n");
return;
}
for (i = 0; i < max; i++)
usage_table[i] = 1;
#ifdef USERSPACE_INTERFACE
if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) {
printk ("mtrr: could not allocate\n");
return;
}
ascii_buf_bytes = 0;
compute_ascii ();
#endif
}
/*
* Get a free MTRR.
* returns the index of the region on success, else -1 on error.
*/
static int get_free_region(void)
{
int i, max;
mtrr_type ltype;
u64 lbase;
u32 lsize;
max = get_num_var_ranges ();
for (i = 0; i < max; ++i) {
get_mtrr (i, &lbase, &lsize, &ltype);
if (lsize == 0)
return i;
}
return -ENOSPC;
}
/**
* mtrr_add_page - Add a memory type region
* @base: Physical base address of region in pages (4 KB)
* @size: Physical size of region in pages (4 KB)
* @type: Type of MTRR desired
* @increment: If this is true do usage counting on the region
* Returns The MTRR register on success, else a negative number
* indicating the error code.
*
* Memory type region registers control the caching on newer
* processors. This function allows drivers to request an MTRR is added.
* The caller should expect to need to provide a power of two size on
* an equivalent power of two boundary.
*
* If the region cannot be added either because all regions are in use
* or the CPU cannot support it a negative value is returned. On success
* the register number for this entry is returned, but should be treated
* as a cookie only.
*
* On a multiprocessor machine the changes are made to all processors.
*
* The available types are
*
* %MTRR_TYPE_UNCACHABLE - No caching
* %MTRR_TYPE_WRBACK - Write data back in bursts whenever
* %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
* %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
*
* BUGS: Needs a quiet flag for the cases where drivers do not mind
* failures and do not wish system log messages to be sent.
*/
int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment)
{
int i, max;
mtrr_type ltype;
u64 lbase, last;
u32 lsize;
if (base + size < 0x100) {
printk (KERN_WARNING
"mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n",
base, size);
return -EINVAL;
}
/* Check upper bits of base and last are equal and lower bits are 0
for base and 1 for last */
last = base + size - 1;
for (lbase = base; !(lbase & 1) && (last & 1);
lbase = lbase >> 1, last = last >> 1) ;
if (lbase != last) {
printk (KERN_WARNING
"mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n",
base, size);
return -EINVAL;
}
if (type >= MTRR_NUM_TYPES) {
printk ("mtrr: type: %u illegal\n", type);
return -EINVAL;
}
/* If the type is WC, check that this processor supports it */
if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {
printk (KERN_WARNING
"mtrr: your processor doesn't support write-combining\n");
return -ENOSYS;
}
if (base & (size_or_mask>>PAGE_SHIFT)) {
printk (KERN_WARNING "mtrr: base(%lx) exceeds the MTRR width(%lx)\n",
(unsigned long) base,
(unsigned long) (size_or_mask>>PAGE_SHIFT));
return -EINVAL;
}
if (size & (size_or_mask>>PAGE_SHIFT)) {
printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n");
return -EINVAL;
}
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
/* Search for existing MTRR */
down (&mtrr_lock);
for (i = 0; i < max; ++i) {
get_mtrr (i, &lbase, &lsize, &ltype);
if (base >= lbase + lsize)
continue;
if ((base < lbase) && (base + size <= lbase))
continue;
/* At this point we know there is some kind of overlap/enclosure */
if ((base < lbase) || (base + size > lbase + lsize)) {
up (&mtrr_lock);
printk (KERN_WARNING
"mtrr: 0x%Lx000,0x%x000 overlaps existing"
" 0x%Lx000,0x%x000\n", base, size, lbase, lsize);
return -EINVAL;
}
/* New region is enclosed by an existing region */
if (ltype != type) {
if (type == MTRR_TYPE_UNCACHABLE)
continue;
up (&mtrr_lock);
printk
("mtrr: type mismatch for %Lx000,%x000 old: %s new: %s\n",
base, size,
attrib_to_str (ltype),
attrib_to_str (type));
return -EINVAL;
}
if (increment)
++usage_table[i];
compute_ascii ();
up (&mtrr_lock);
return i;
}
/* Search for an empty MTRR */
i = get_free_region();
if (i < 0) {
up (&mtrr_lock);
printk ("mtrr: no more MTRRs available\n");
return i;
}
set_mtrr (i, base, size, type);
usage_table[i] = 1;
compute_ascii ();
up (&mtrr_lock);
return i;
}
/**
* mtrr_add - Add a memory type region
* @base: Physical base address of region
* @size: Physical size of region
* @type: Type of MTRR desired
* @increment: If this is true do usage counting on the region
* Return the MTRR register on success, else a negative numbe
* indicating the error code.
*
* Memory type region registers control the caching on newer processors.
* This function allows drivers to request an MTRR is added.
* The caller should expect to need to provide a power of two size on
* an equivalent power of two boundary.
*
* If the region cannot be added either because all regions are in use
* or the CPU cannot support it a negative value is returned. On success
* the register number for this entry is returned, but should be treated
* as a cookie only.
*
* On a multiprocessor machine the changes are made to all processors.
* This is required on x86 by the Intel processors.
*
* The available types are
*
* %MTRR_TYPE_UNCACHABLE - No caching
* %MTRR_TYPE_WRBACK - Write data back in bursts whenever
* %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
* %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
*
* BUGS: Needs a quiet flag for the cases where drivers do not mind
* failures and do not wish system log messages to be sent.
*/
int mtrr_add (u64 base, u32 size, unsigned int type, char increment)
{
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
printk ("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base);
return -EINVAL;
}
return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
increment);
}
/**
* mtrr_del_page - delete a memory type region
* @reg: Register returned by mtrr_add
* @base: Physical base address
* @size: Size of region
*
* If register is supplied then base and size are ignored. This is
* how drivers should call it.
*
* Releases an MTRR region. If the usage count drops to zero the
* register is freed and the region returns to default state.
* On success the register is returned, on failure a negative error
* code.
*/
int mtrr_del_page (int reg, u64 base, u32 size)
{
int i, max;
mtrr_type ltype;
u64 lbase;
u32 lsize;
max = get_num_var_ranges ();
down (&mtrr_lock);
if (reg < 0) {
/* Search for existing MTRR */
for (i = 0; i < max; ++i) {
get_mtrr (i, &lbase, &lsize, &ltype);
if (lbase == base && lsize == size) {
reg = i;
break;
}
}
if (reg < 0) {
up (&mtrr_lock);
printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size);
return -EINVAL;
}
}
if (reg >= max) {
up (&mtrr_lock);
printk ("mtrr: register: %d too big\n", reg);
return -EINVAL;
}
get_mtrr (reg, &lbase, &lsize, &ltype);
if (lsize < 1) {
up (&mtrr_lock);
printk ("mtrr: MTRR %d not used\n", reg);
return -EINVAL;
}
if (usage_table[reg] < 1) {
up (&mtrr_lock);
printk ("mtrr: reg: %d has count=0\n", reg);
return -EINVAL;
}
if (--usage_table[reg] < 1)
set_mtrr (reg, 0, 0, 0);
compute_ascii ();
up (&mtrr_lock);
return reg;
}
/**
* mtrr_del - delete a memory type region
* @reg: Register returned by mtrr_add
* @base: Physical base address
* @size: Size of region
*
* If register is supplied then base and size are ignored. This is
* how drivers should call it.
*
* Releases an MTRR region. If the usage count drops to zero the
* register is freed and the region returns to default state.
* On success the register is returned, on failure a negative error
* code.
*/
int mtrr_del (int reg, u64 base, u32 size)
{
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
printk ("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base);
return -EINVAL;
}
return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
}
#ifdef USERSPACE_INTERFACE
static int mtrr_file_add (u64 base, u32 size, unsigned int type,
struct file *file, int page)
{
int reg, max;
unsigned int *fcount = file->private_data;
max = get_num_var_ranges ();
if (fcount == NULL) {
if ((fcount =
kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) {
printk ("mtrr: could not allocate\n");
return -ENOMEM;
}
memset (fcount, 0, max * sizeof *fcount);
file->private_data = fcount;
}
if (!page) {
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
printk
("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base);
return -EINVAL;
}
base >>= PAGE_SHIFT;
size >>= PAGE_SHIFT;
}
reg = mtrr_add_page (base, size, type, 1);
if (reg >= 0)
++fcount[reg];
return reg;
}
static int mtrr_file_del (u64 base, u32 size,
struct file *file, int page)
{
int reg;
unsigned int *fcount = file->private_data;
if (!page) {
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
printk
("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base);
return -EINVAL;
}
base >>= PAGE_SHIFT;
size >>= PAGE_SHIFT;
}
reg = mtrr_del_page (-1, base, size);
if (reg < 0)
return reg;
if (fcount == NULL)
return reg;
if (fcount[reg] < 1)
return -EINVAL;
--fcount[reg];
return reg;
}
static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
loff_t * ppos)
{
if (*ppos >= ascii_buf_bytes)
return 0;
if (*ppos + len > ascii_buf_bytes)
len = ascii_buf_bytes - *ppos;
if (copy_to_user (buf, ascii_buffer + *ppos, len))
return -EFAULT;
*ppos += len;
return len;
}
static ssize_t mtrr_write (struct file *file, const char *buf,
size_t len, loff_t * ppos)
/* Format of control line:
"base=%Lx size=%Lx type=%s" OR:
"disable=%d"
*/
{
int i, err, reg;
u64 base;
u32 size;
char *ptr;
char line[LINE_SIZE];
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
/* Can't seek (pwrite) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
memset (line, 0, LINE_SIZE);
if (len > LINE_SIZE)
len = LINE_SIZE;
if (copy_from_user (line, buf, len - 1))
return -EFAULT;
ptr = line + strlen (line) - 1;
if (*ptr == '\n')
*ptr = '\0';
if (!strncmp (line, "disable=", 8)) {
reg = simple_strtoul (line + 8, &ptr, 0);
err = mtrr_del_page (reg, 0, 0);
if (err < 0)
return err;
return len;
}
if (strncmp (line, "base=", 5)) {
printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
return -EINVAL;
}
base = simple_strtoull (line + 5, &ptr, 0);
for (; isspace (*ptr); ++ptr) ;
if (strncmp (ptr, "size=", 5)) {
printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);
return -EINVAL;
}
size = simple_strtoull (ptr + 5, &ptr, 0);
if ((base & 0xfff) || (size & 0xfff)) {
printk ("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base);
return -EINVAL;
}
for (; isspace (*ptr); ++ptr) ;
if (strncmp (ptr, "type=", 5)) {
printk ("mtrr: no \"type=\" in line: \"%s\"\n", line);
return -EINVAL;
}
ptr += 5;
for (; isspace (*ptr); ++ptr) ;
for (i = 0; i < MTRR_NUM_TYPES; ++i) {
if (strcmp (ptr, mtrr_strings[i]))
continue;
base >>= PAGE_SHIFT;
size >>= PAGE_SHIFT;
err = mtrr_add_page ((u64) base, size, i, 1);
if (err < 0)
return err;
return len;
}
printk ("mtrr: illegal type: \"%s\"\n", ptr);
return -EINVAL;
}
static int mtrr_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err;
mtrr_type type;
struct mtrr_sentry sentry;
struct mtrr_gentry gentry;
switch (cmd) {
default:
return -ENOIOCTLCMD;
case MTRRIOC_ADD_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_file_add (sentry.base, sentry.size, sentry.type,
file, 0);
if (err < 0)
return err;
break;
case MTRRIOC_SET_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
if (err < 0)
return err;
break;
case MTRRIOC_DEL_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_file_del (sentry.base, sentry.size, file, 0);
if (err < 0)
return err;
break;
case MTRRIOC_KILL_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_del (-1, sentry.base, sentry.size);
if (err < 0)
return err;
break;
case MTRRIOC_GET_ENTRY:
if (copy_from_user (&gentry, (void *) arg, sizeof gentry))
return -EFAULT;
if (gentry.regnum >= get_num_var_ranges ())
return -EINVAL;
get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
/* Hide entries that go above 4GB */
if (gentry.base + gentry.size > 0x100000
|| gentry.size == 0x100000)
gentry.base = gentry.size = gentry.type = 0;
else {
gentry.base <<= PAGE_SHIFT;
gentry.size <<= PAGE_SHIFT;
gentry.type = type;
}
if (copy_to_user ((void *) arg, &gentry, sizeof gentry))
return -EFAULT;
break;
case MTRRIOC_ADD_PAGE_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1);
if (err < 0)
return err;
break;
case MTRRIOC_SET_PAGE_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
if (err < 0)
return err;
break;
case MTRRIOC_DEL_PAGE_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_file_del (sentry.base, sentry.size, file, 1);
if (err < 0)
return err;
break;
case MTRRIOC_KILL_PAGE_ENTRY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
return -EFAULT;
err = mtrr_del_page (-1, sentry.base, sentry.size);
if (err < 0)
return err;
break;
case MTRRIOC_GET_PAGE_ENTRY:
if (copy_from_user (&gentry, (void *) arg, sizeof gentry))
return -EFAULT;
if (gentry.regnum >= get_num_var_ranges ())
return -EINVAL;
get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
gentry.type = type;
if (copy_to_user ((void *) arg, &gentry, sizeof gentry))
return -EFAULT;
break;
}
return 0;
}
static int mtrr_close (struct inode *ino, struct file *file)
{
int i, max;
unsigned int *fcount = file->private_data;
if (fcount == NULL)
return 0;
lock_kernel ();
max = get_num_var_ranges ();
for (i = 0; i < max; ++i) {
while (fcount[i] > 0) {
if (mtrr_del (i, 0, 0) < 0)
printk ("mtrr: reg %d not used\n", i);
--fcount[i];
}
}
unlock_kernel ();
kfree (fcount);
file->private_data = NULL;
return 0;
}
static struct file_operations mtrr_fops = {
.owner = THIS_MODULE,
.read = mtrr_read,
.write = mtrr_write,
.ioctl = mtrr_ioctl,
.release = mtrr_close,
};
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_root_mtrr;
#endif
static devfs_handle_t devfs_handle;
static void compute_ascii (void)
{
char factor;
int i, max;
mtrr_type type;
u64 base;
u32 size;
ascii_buf_bytes = 0;
max = get_num_var_ranges ();
for (i = 0; i < max; i++) {
get_mtrr (i, &base, &size, &type);
if (size == 0)
usage_table[i] = 0;
else {
if (size < (0x100000 >> PAGE_SHIFT)) {
/* less than 1MB */
factor = 'K';
size <<= PAGE_SHIFT - 10;
} else {
factor = 'M';
size >>= 20 - PAGE_SHIFT;
}
sprintf (ascii_buffer + ascii_buf_bytes,
"reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n",
i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor,
attrib_to_str (type), usage_table[i]);
ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
}
}
devfs_set_file_size (devfs_handle, ascii_buf_bytes);
#ifdef CONFIG_PROC_FS
if (proc_root_mtrr)
proc_root_mtrr->size = ascii_buf_bytes;
#endif
}
#endif /* USERSPACE_INTERFACE */
EXPORT_SYMBOL (mtrr_add);
EXPORT_SYMBOL (mtrr_del);
static void __init mtrr_setup (void)
{
/* If you want to use other vendors please port over the modular
framework from i386 first. */
if (!cpu_has_mtrr || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return;
/* Query the width (in bits) of the physical
addressable memory on the Hammer family. */
if ((cpuid_eax (0x80000000) >= 0x80000008)) {
u32 phys_addr;
phys_addr = cpuid_eax (0x80000008) & 0xff;
size_or_mask = ~((1L << phys_addr) - 1);
/*
* top bits MBZ as its beyond the addressable range.
* bottom bits MBZ as we don't care about lower 12 bits of addr.
*/
size_and_mask = (~size_or_mask) & 0x000ffffffffff000L;
}
}
#ifdef CONFIG_SMP
static volatile u32 smp_changes_mask __initdata = 0;
static struct mtrr_state smp_mtrr_state __initdata = { 0, 0 };
#endif /* CONFIG_SMP */
void mtrr_init_cpu(int cpu)
{
#ifndef CONFIG_SMP
if (cpu == 0)
mtrr_setup();
#else
if (cpu == 0) {
mtrr_setup();
get_mtrr_state (&smp_mtrr_state);
} else {
u64 mask;
int count;
struct set_mtrr_context ctxt;
/* Note that this is not ideal, since the cache is
only flushed/disabled for this CPU while the MTRRs
are changed, but changing this requires more
invasive changes to the way the kernel boots */
set_mtrr_prepare (&ctxt);
mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
set_mtrr_done (&ctxt);
/* Use the atomic bitops to update the global mask */
for (count = 0; count < (sizeof mask) * 8; ++count) {
if (mask & 1)
set_bit (count, &smp_changes_mask);
mask >>= 1;
}
}
#endif
}
static int __init mtrr_init (void)
{
#ifdef CONFIG_PROC_FS
proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
if (proc_root_mtrr) {
proc_root_mtrr->owner = THIS_MODULE;
proc_root_mtrr->proc_fops = &mtrr_fops;
}
#endif
#ifdef CONFIG_DEVFS_FS
devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0,
S_IFREG | S_IRUGO | S_IWUSR,
&mtrr_fops, NULL);
#endif
init_table ();
#ifdef CONFIG_SMP
finalize_mtrr_state (&smp_mtrr_state);
mtrr_state_warn (smp_changes_mask);
#endif
return 0;
}
__initcall(mtrr_init);
#
# Reuse the i386 MTRR driver.
#
obj-y := main.o if.o generic.o state.o
obj-y += amd.o
obj-y += cyrix.o
obj-y += centaur.o
export-objs := main.o
$(obj)/main.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/main.c $(obj)/main.c
$(obj)/if.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/if.c $(obj)/if.c
$(obj)/generic.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/generic.c $(obj)/generic.c
$(obj)/state.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/state.c $(obj)/state.c
$(obj)/amd.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/amd.c $(obj)/amd.c
$(obj)/cyrix.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/cyrix.c $(obj)/cyrix.c
$(obj)/centaur.c: $(obj)/mtrr.h
@ln -sf ../../../i386/kernel/cpu/mtrr/centaur.c $(obj)/centaur.c
$(obj)/mtrr.h:
@ln -sf ../../../i386/kernel/cpu/mtrr/mtrr.h $(obj)/mtrr.h
clean-files += main.c if.c generic.c state.c amd.c cyrix.c centaur.c mtrr.h
......@@ -300,12 +300,18 @@ static nmi_callback_t nmi_callback = dummy_nmi_callback;
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
int cpu = smp_processor_id();
int cpu;
nmi_enter();
cpu = smp_processor_id();
add_pda(__nmi_count,1);
if (!nmi_callback(regs, cpu))
default_do_nmi(regs);
nmi_exit();
}
void set_nmi_callback(nmi_callback_t callback)
......
......@@ -245,7 +245,7 @@ static void iommu_full(struct pci_dev *dev, void *addr, size_t size, int dir)
printk(KERN_ERR
"PCI-DMA: Error: ran out out IOMMU space for %p size %lu at device %s[%s]\n",
addr,size, dev ? dev->name : "?", dev ? dev->slot_name : "?");
addr,size, dev ? dev->dev.name : "?", dev ? dev->slot_name : "?");
if (size > PAGE_SIZE*EMERGENCY_PAGES) {
if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
......@@ -286,7 +286,7 @@ dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
if (!need_iommu(dev, phys_mem, size))
return phys_mem;
npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
npages = round_up(size + ((u64)addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
iommu_page = alloc_iommu(npages);
if (iommu_page == -1) {
......@@ -328,7 +328,7 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
dma_addr > iommu_bus_base + iommu_size)
return;
iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
npages = round_up(size + (dma_addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
for (i = 0; i < npages; i++) {
iommu_gatt_base[iommu_page + i] = 0;
#ifdef CONFIG_IOMMU_LEAK
......
......@@ -24,6 +24,7 @@
#include <linux/sched.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>
......@@ -223,6 +224,7 @@ 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..
*/
......@@ -259,7 +261,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
if (rsp == ~0) {
childregs->rsp = (unsigned long)childregs;
}
p->user_tid = NULL;
p->set_child_tid = p->clear_child_tid = NULL;
p->thread.rsp = (unsigned long) childregs;
p->thread.rsp0 = (unsigned long) (childregs+1);
......@@ -322,10 +324,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
/*
* switch_to(x,y) 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.
*
* This could still be optimized:
* - fold all the options into a flag word and test it with a single test.
* - could test fs/gs bitsliced
......@@ -356,44 +354,37 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
if (unlikely(next->ds | prev->ds))
loadsegment(ds, next->ds);
load_TLS(next, cpu);
/*
* Switch FS and GS.
* XXX Check if this is safe on SMP (!= -> |)
* Need to simplify this.
*/
{
unsigned int fsindex;
unsigned int gsindex;
unsigned fsindex;
asm volatile("movl %%fs,%0" : "=g" (fsindex));
asm volatile("movl %%gs,%0" : "=g" (gsindex));
/*
* Load the per-thread Thread-Local Storage descriptor.
*/
if (load_TLS(next, cpu)) {
loadsegment(fs,next->fsindex);
/* should find a way to optimize this away - it is
slow */
goto loadgs;
} else {
if (fsindex != next->fsindex)
loadsegment(fs,next->fsindex);
if (gsindex != next->gsindex) {
loadgs:
load_gs_index(next->gsindex);
}
}
/* segment register != 0 always requires a reload.
also reload when it has changed.
when prev process used 64bit base always reload
to avoid an information leak. */
if (unlikely((fsindex | next->fsindex) || prev->fs))
loadsegment(fs, next->fsindex);
/* check if the user changed the selector
if yes clear 64bit base. */
if (unlikely(fsindex != prev->fsindex))
prev->fs = 0;
if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
/* when next process has a 64bit base use it */
if (next->fs)
wrmsrl(MSR_FS_BASE, next->fs);
prev->fsindex = fsindex;
}
{
unsigned gsindex;
asm volatile("movl %%gs,%0" : "=g" (gsindex));
if (unlikely((gsindex | next->gsindex) || prev->gs))
load_gs_index(next->gsindex);
if (unlikely(gsindex != prev->gsindex))
prev->gs = 0;
if (gsindex != prev->gsindex || prev->gs != next->gs)
if (next->gs)
wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
prev->gsindex = gsindex;
}
......@@ -477,16 +468,17 @@ void set_personality_64bit(void)
asmlinkage long sys_fork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL);
p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *user_tid, struct pt_regs regs)
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *parent_tid, void *child_tid, struct pt_regs regs)
{
struct task_struct *p;
if (!newsp)
newsp = regs.rsp;
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
parent_tid, child_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -503,7 +495,8 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *
asmlinkage long sys_vfork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL);
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0,
NULL, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -547,7 +540,8 @@ int sys_arch_prctl(int code, unsigned long addr)
case ARCH_SET_GS:
if (addr >= TASK_SIZE)
return -EPERM;
asm volatile("movw %%gs,%0" : "=g" (current->thread.gsindex));
load_gs_index(0);
current->thread.gsindex = 0;
current->thread.gs = addr;
ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
break;
......@@ -556,7 +550,8 @@ int sys_arch_prctl(int code, unsigned long addr)
with gs */
if (addr >= TASK_SIZE)
return -EPERM;
asm volatile("movw %%fs,%0" : "=g" (current->thread.fsindex));
asm volatile("movl %0,%%fs" :: "r" (0));
current->thread.fsindex = 0;
current->thread.fs = addr;
ret = checking_wrmsrl(MSR_FS_BASE, addr);
break;
......@@ -691,3 +686,22 @@ asmlinkage int sys_get_thread_area(struct user_desc *u_info)
return -EFAULT;
return 0;
}
/*
* Capture the user space registers if the task is not running (in user space)
*/
int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
{
struct pt_regs *pp, ptregs;
pp = (struct pt_regs *)(tsk->thread.rsp0);
--pp;
ptregs = *pp;
ptregs.cs &= 0xffff;
ptregs.ss &= 0xffff;
elf_core_copy_regs(regs, &ptregs);
return 1;
}
/*
* linux/arch/i386/kernel/profile.c
* linux/arch/x86_64/kernel/profile.c
*
* (C) 2002 John Levon <levon@movementarian.org>
*
......
......@@ -41,6 +41,23 @@ struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table };
char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
unsigned long __supported_pte_mask = ~0UL;
static int do_not_nx = 0;
static int __init nonx_setup(char *str)
{
if (!strncmp(str,"off",3)) {
__supported_pte_mask &= ~_PAGE_NX;
do_not_nx = 1;
} else if (!strncmp(str, "on",3)) {
do_not_nx = 0;
__supported_pte_mask |= _PAGE_NX;
}
return 1;
}
__setup("noexec=", nonx_setup);
#ifndef __GENERIC_PER_CPU
unsigned long __per_cpu_offset[NR_CPUS];
......@@ -127,7 +144,7 @@ void __init cpu_init (void)
int cpu = smp_processor_id();
#endif
struct tss_struct * t = &init_tss[cpu];
unsigned long v;
unsigned long v, efer;
char *estacks;
struct task_struct *me;
......@@ -189,6 +206,11 @@ void __init cpu_init (void)
wrmsrl(MSR_KERNEL_GS_BASE, 0);
barrier();
rdmsrl(MSR_EFER, efer);
if (!(efer & EFER_NX) || do_not_nx) {
__supported_pte_mask &= ~_PAGE_NX;
}
/*
* set up and load the per-CPU TSS
*/
......
......@@ -24,9 +24,11 @@
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/compiler.h>
#include <linux/suspend.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/proto.h>
/* #define DEBUG_SIG 1 */
......@@ -184,11 +186,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
* Set up a signal frame.
*/
static int
setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask)
static inline int
setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me)
{
int tmp, err = 0;
struct task_struct *me = current;
tmp = 0;
__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
......@@ -226,8 +227,6 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask
* Determine which stack to use..
*/
#define round_down(p, r) ((void *) ((unsigned long)((p) - (r) + 1) & ~((r)-1)))
static void *
get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
{
......@@ -242,19 +241,20 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
rsp = current->sas_ss_sp + current->sas_ss_size;
}
return round_down(rsp - size, 16);
return (void *)round_down(rsp - size, 16);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs)
{
struct rt_sigframe *frame = NULL;
struct rt_sigframe *frame;
struct _fpstate *fp = NULL;
int err = 0;
struct task_struct *me = current;
if (current->used_math) {
if (me->used_math) {
fp = get_stack(ka, regs, sizeof(struct _fpstate));
frame = round_down((char *)fp - sizeof(struct rt_sigframe), 16) - 8;
frame = (void *)round_down((u64)fp - sizeof(struct rt_sigframe), 16) - 8;
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) {
goto give_sigsegv;
......@@ -262,10 +262,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (save_i387(fp) < 0)
err |= -1;
}
if (!frame)
} else {
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
}
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
goto give_sigsegv;
......@@ -281,13 +280,18 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* 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(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->rsp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me);
err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
if (sizeof(*set) == 16) {
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
} else {
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
......@@ -295,7 +299,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (ka->sa.sa_flags & SA_RESTORER) {
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
printk("%s forgot to set SA_RESTORER for signal %d.\n", current->comm, sig);
printk("%s forgot to set SA_RESTORER for signal %d.\n", me->comm, sig);
goto give_sigsegv;
}
......@@ -338,7 +342,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
signal_fault(regs,frame,"signal setup");
signal_fault(regs,frame,"signal deliver");
}
/*
......@@ -360,6 +364,9 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
if (regs->orig_rax >= 0) {
/* If so, check system call restarting.. */
switch (regs->rax) {
case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* FALL THROUGH */
case -ERESTARTNOHAND:
regs->rax = -EINTR;
break;
......@@ -374,6 +381,10 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
regs->rax = regs->orig_rax;
regs->rip -= 2;
}
if (regs->rax == -ERESTART_RESTARTBLOCK){
regs->rax = __NR_restart_syscall;
regs->rip -= 2;
}
}
#ifdef CONFIG_IA32_EMULATION
......@@ -418,6 +429,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
return 1;
}
if (current->flags & PF_FREEZE) {
refrigerator(0);
goto no_signal;
}
if (!oldset)
oldset = &current->blocked;
......@@ -435,6 +451,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
return 1;
}
no_signal:
/* Did we come from a system call? */
if (regs->orig_rax >= 0) {
/* Restart the system call - no handlers present */
......
......@@ -18,11 +18,11 @@
#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/interrupt.h>
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/hardirq.h>
/*
* the following functions deal with sending IPIs between CPUs.
......
......@@ -323,12 +323,6 @@ void __init smp_callin(void)
local_irq_enable();
#ifdef CONFIG_MTRR
/*
* Must be done before calibration delay is computed
*/
mtrr_init_cpu (cpuid);
#endif
/*
* Get our bogomips.
*/
......@@ -344,6 +338,8 @@ void __init smp_callin(void)
notify_die(DIE_CPUINIT, "cpuinit", NULL, 0);
local_irq_disable();
/*
* Allow the master to continue.
*/
......@@ -436,7 +432,7 @@ static struct task_struct * __init fork_by_hand(void)
* don't care about the rip and regs settings since
* we'll never reschedule the forked task.
*/
return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL);
return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
}
#if APIC_DEBUG
......@@ -969,12 +965,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
int __devinit __cpu_up(unsigned int cpu)
{
/* This only works at boot for x86. See "rewrite" above. */
if (test_bit(cpu, &smp_commenced_mask))
if (test_bit(cpu, &smp_commenced_mask)) {
local_irq_enable();
return -ENOSYS;
}
/* In case one didn't come up */
if (!test_bit(cpu, &cpu_callin_map))
if (!test_bit(cpu, &cpu_callin_map)) {
local_irq_enable();
return -EIO;
}
local_irq_enable();
/* Unleash the CPU! */
Dprintk("waiting for cpu %d\n", cpu);
......
/*
* Suspend support specific for i386.
*
* Distribute under GPLv2
*
* Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/sysrq.h>
#include <linux/compatmac.h>
#include <linux/proc_fs.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/suspend.h>
#include <asm/uaccess.h>
#include <asm/acpi.h>
#include <asm/tlbflush.h>
#include <asm/io.h>
static struct saved_context saved_context;
unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx;
unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi;
unsigned long saved_context_r08, saved_context_r09, saved_context_r10, saved_context_r11;
unsigned long saved_context_r12, saved_context_r13, saved_context_r14, saved_context_r15;
unsigned long saved_context_eflags;
void save_processor_state (void)
{
kernel_fpu_begin();
/*
* descriptor tables
*/
asm volatile ("sgdt %0" : "=m" (saved_context.gdt_limit));
asm volatile ("sidt %0" : "=m" (saved_context.idt_limit));
asm volatile ("sldt %0" : "=m" (saved_context.ldt));
asm volatile ("str %0" : "=m" (saved_context.tr));
/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
/* EFER should be constant for kernel version, no need to handle it. */
/*
* segment registers
*/
asm volatile ("movw %%ds, %0" : "=m" (saved_context.ds));
asm volatile ("movw %%es, %0" : "=m" (saved_context.es));
asm volatile ("movw %%fs, %0" : "=m" (saved_context.fs));
asm volatile ("movw %%gs, %0" : "=m" (saved_context.gs));
asm volatile ("movw %%ss, %0" : "=m" (saved_context.ss));
asm volatile ("swapgs");
rdmsrl(0xc0000100, saved_context.fs_base);
rdmsrl(0xc0000101, saved_context.gs_base);
asm volatile ("swapgs");
/*
* control registers
*/
asm volatile ("movq %%cr0, %0" : "=r" (saved_context.cr0));
asm volatile ("movq %%cr2, %0" : "=r" (saved_context.cr2));
asm volatile ("movq %%cr3, %0" : "=r" (saved_context.cr3));
asm volatile ("movq %%cr4, %0" : "=r" (saved_context.cr4));
}
static void
do_fpu_end(void)
{
/* restore FPU regs if necessary */
/* Do it out of line so that gcc does not move cr0 load to some stupid place */
kernel_fpu_end();
}
void restore_processor_state(void)
{
/*
* control registers
*/
asm volatile ("movq %0, %%cr4" :: "r" (saved_context.cr4));
asm volatile ("movq %0, %%cr3" :: "r" (saved_context.cr3));
asm volatile ("movq %0, %%cr2" :: "r" (saved_context.cr2));
asm volatile ("movq %0, %%cr0" :: "r" (saved_context.cr0));
/*
* segment registers
*/
asm volatile ("movw %0, %%ds" :: "r" (saved_context.ds));
asm volatile ("movw %0, %%es" :: "r" (saved_context.es));
asm volatile ("movw %0, %%fs" :: "r" (saved_context.fs));
load_gs_index(saved_context.gs);
asm volatile ("movw %0, %%ss" :: "r" (saved_context.ss));
asm volatile ("swapgs");
wrmsrl(0xc0000100, saved_context.fs_base);
wrmsrl(0xc0000101, saved_context.gs_base);
asm volatile ("swapgs");
/*
* now restore the descriptor tables to their proper values
* ltr is done i fix_processor_context().
*/
asm volatile ("lgdt %0" :: "m" (saved_context.gdt_limit));
asm volatile ("lidt %0" :: "m" (saved_context.idt_limit));
asm volatile ("lldt %0" :: "m" (saved_context.ldt));
fix_processor_context();
do_fpu_end();
}
void fix_processor_context(void)
{
int cpu = smp_processor_id();
struct tss_struct * t = init_tss + cpu;
printk("Should fix processor context!\n");
load_LDT(&current->mm->context); /* This does lldt */
/*
* Now maybe reload the debug registers
*/
if (current->thread.debugreg[7]){
loaddebug(&current->thread, 0);
loaddebug(&current->thread, 1);
loaddebug(&current->thread, 2);
loaddebug(&current->thread, 3);
/* no 4 and 5 */
loaddebug(&current->thread, 6);
loaddebug(&current->thread, 7);
}
}
/* originally gcc generated, but now changed. don't overwrite. */
.text
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
/* Input:
* rdi resume flag
*/
ENTRY(do_magic)
.LFB5:
subq $8, %rsp
.LCFI2:
testl %edi, %edi
jne .L90
call do_magic_suspend_1
call save_processor_state
movq %rsp, saved_context_esp(%rip)
movq %rax, saved_context_eax(%rip)
movq %rbx, saved_context_ebx(%rip)
movq %rcx, saved_context_ecx(%rip)
movq %rdx, saved_context_edx(%rip)
movq %rbp, saved_context_ebp(%rip)
movq %rsi, saved_context_esi(%rip)
movq %rdi, saved_context_edi(%rip)
movq %r8, saved_context_r08(%rip)
movq %r9, saved_context_r09(%rip)
movq %r10, saved_context_r10(%rip)
movq %r11, saved_context_r11(%rip)
movq %r12, saved_context_r12(%rip)
movq %r13, saved_context_r13(%rip)
movq %r14, saved_context_r14(%rip)
movq %r15, saved_context_r15(%rip)
pushfq ; popq saved_context_eflags(%rip)
addq $8, %rsp
jmp do_magic_suspend_2
.L90:
/* set up cr3 */
leaq init_level4_pgt(%rip),%rax
subq $__START_KERNEL_map,%rax
movq %rax,%cr3
movq mmu_cr4_features(%rip), %rax
movq %rax, %rdx
andq $~(1<<7), %rdx # PGE
movq %rdx, %cr4; # turn off PGE
movq %cr3, %rcx; # flush TLB
movq %rcx, %cr3;
movq %rax, %cr4; # turn PGE back on
call do_magic_resume_1
movl nr_copy_pages(%rip), %eax
xorl %ecx, %ecx
movq $0, loop(%rip)
testl %eax, %eax
je .L108
.L105:
xorl %esi, %esi
movq $0, loop2(%rip)
jmp .L104
.p2align 4,,7
.L111:
movq loop(%rip), %rcx
.L104:
movq pagedir_nosave(%rip), %rdx
movq %rcx, %rax
salq $5, %rax
movq 8(%rdx,%rax), %rcx
movq (%rdx,%rax), %rax
movzbl (%rsi,%rax), %eax
movb %al, (%rsi,%rcx)
movq %cr3, %rax; # flush TLB
movq %rax, %cr3;
movq loop2(%rip), %rax
incq %rax
cmpq $4095, %rax
movq %rax, %rsi
movq %rax, loop2(%rip)
jbe .L111
movq loop(%rip), %rax
incq %rax
movq %rax, %rcx
movq %rax, loop(%rip)
mov nr_copy_pages(%rip), %eax
cmpq %rax, %rcx
jb .L105
.L108:
.align 4
movl $24, %eax
movl %eax, %ds
movq saved_context_esp(%rip), %rsp
movq saved_context_ebp(%rip), %rbp
movq saved_context_eax(%rip), %rax
movq saved_context_ebx(%rip), %rbx
movq saved_context_ecx(%rip), %rcx
movq saved_context_edx(%rip), %rdx
movq saved_context_esi(%rip), %rsi
movq saved_context_edi(%rip), %rdi
movq saved_context_r08(%rip), %r8
movq saved_context_r09(%rip), %r9
movq saved_context_r10(%rip), %r10
movq saved_context_r11(%rip), %r11
movq saved_context_r12(%rip), %r12
movq saved_context_r13(%rip), %r13
movq saved_context_r14(%rip), %r14
movq saved_context_r15(%rip), %r15
pushq saved_context_eflags(%rip) ; popfq
call restore_processor_state
addq $8, %rsp
jmp do_magic_resume_2
.section .data.nosave
loop:
.quad 0
loop2:
.quad 0
.previous
\ No newline at end of file
......@@ -83,22 +83,18 @@ static int kstack_depth_to_print = 10;
#include <linux/kallsyms.h>
int printk_address(unsigned long address)
{
unsigned long dummy;
const char *modname, *secname, *symname;
unsigned long symstart;
unsigned long offset = 0, symsize;
const char *symname;
char *modname;
char *delim = ":";
/* What a function call! */
if (!kallsyms_address_to_symbol(address,
&modname, &dummy, &dummy,
&secname, &dummy, &dummy,
&symname, &symstart, &dummy)) {
symname = kallsyms_lookup(address, &symsize, &offset, &modname);
if (!symname)
return printk("[<%016lx>]", address);
}
if (!strcmp(modname, "kernel"))
if (!modname)
modname = delim = "";
return printk("<%016lx>{%s%s%s%s%+ld}",
address,delim,modname,delim,symname,address-symstart);
address,delim,modname,delim,symname,offset);
}
#else
int printk_address(unsigned long address)
......@@ -110,7 +106,8 @@ int printk_address(unsigned long address)
#ifdef CONFIG_MODULES
extern struct module kernel_module;
/* FIXME: Accessed without a lock --RR */
extern struct list_head modules;
static inline int kernel_text_address(unsigned long addr)
{
......@@ -121,11 +118,11 @@ static inline int kernel_text_address(unsigned long addr)
addr <= (unsigned long) &_etext)
return 1;
for (mod = module_list; mod != &kernel_module; mod = mod->next) {
list_for_each_entry(mod, &modules, list) {
/* mod_bound tests for addr being inside the vmalloc'ed
* module area. Of course it'd be better to test only
* for the .text subset... */
if (mod_bound(addr, 0, mod)) {
if (mod_bound((void *)addr, 0, mod)) {
retval = 1;
break;
}
......@@ -173,7 +170,7 @@ void show_trace(unsigned long *stack)
int i;
printk("\nCall Trace:");
i = 12;
i = 0;
estack_end = in_exception_stack(cpu, (unsigned long)stack);
if (estack_end) {
......
......@@ -2,7 +2,6 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/user.h>
#include <linux/mca.h>
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
......@@ -46,7 +45,7 @@ extern unsigned long get_cmos_time(void);
/* platform dependent support */
EXPORT_SYMBOL(boot_cpu_data);
EXPORT_SYMBOL(dump_fpu);
//EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
......@@ -120,10 +119,6 @@ EXPORT_SYMBOL(smp_call_function);
#endif
#ifdef CONFIG_MCA
EXPORT_SYMBOL(machine_id);
#endif
#ifdef CONFIG_VT
EXPORT_SYMBOL(screen_info);
#endif
......@@ -199,3 +194,6 @@ void out_of_line_bug(void);
EXPORT_SYMBOL(out_of_line_bug);
EXPORT_SYMBOL(init_level4_pgt);
extern unsigned long __supported_pte_mask;
EXPORT_SYMBOL(__supported_pte_mask);
......@@ -2,12 +2,12 @@
#include <asm/io.h>
#include <linux/module.h>
void *memcpy_toio(void *dst,void*src,unsigned len)
void *memcpy_toio(void *dst,const void*src,unsigned len)
{
return __inline_memcpy(__io_virt(dst),src,len);
}
void *memcpy_fromio(void *dst,void*src,unsigned len)
void *memcpy_fromio(void *dst,const void*src,unsigned len)
{
return __inline_memcpy(dst,__io_virt(src),len);
}
......
......@@ -30,7 +30,7 @@ do { \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .align 8\n" \
" .quad 0b,3b\n" \
".previous" \
: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
......
......@@ -5,3 +5,4 @@
export-objs := pageattr.o
obj-y := init.o fault.o ioremap.o extable.o modutil.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
......@@ -62,14 +62,16 @@ search_exception_table(unsigned long addr)
return search_one_table(__start___ex_table, __stop___ex_table-1, addr);
#else
/* The kernel is the last "module" -- no need to treat it special. */
struct module *mp;
struct list_head *i;
spin_lock_irqsave(&modlist_lock, flags);
for (mp = module_list; mp != NULL; mp = mp->next) {
if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
list_for_each(i, &extables) {
struct exception_table *ex =
list_entry(i,struct exception_table, list);
if (ex->num_entries == 0)
continue;
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr);
ret = search_one_table(ex->entry,
ex->entry + ex->num_entries - 1, addr);
if (ret)
break;
}
......
......@@ -300,6 +300,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
pmd_t *pmd;
pte_t *pte;
printk("vmalloc_fault err %lx addr %lx rip %lx\n",
error_code, address, regs->rip);
/*
* x86-64 has the same kernel 3rd level pages for all CPUs.
* But for vmalloc/modules the TLB synchronization works lazily,
......
/*
* x86-64 Huge TLB Page Support for Kernel.
*
* Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com>
* Minor hacks by Andi Kleen for x86-64
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/sysctl.h>
#include <asm/mman.h>
#include <asm/pgalloc.h>
#include <asm/tlb.h>
#include <asm/tlbflush.h>
static long htlbpagemem;
int htlbpage_max;
static long htlbzone_pages;
struct vm_operations_struct hugetlb_vm_ops;
static LIST_HEAD(htlbpage_freelist);
static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
static struct page *alloc_hugetlb_page(void)
{
int i;
struct page *page;
spin_lock(&htlbpage_lock);
if (list_empty(&htlbpage_freelist)) {
spin_unlock(&htlbpage_lock);
return NULL;
}
page = list_entry(htlbpage_freelist.next, struct page, list);
list_del(&page->list);
htlbpagemem--;
spin_unlock(&htlbpage_lock);
set_page_count(page, 1);
for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i)
clear_highpage(&page[i]);
return page;
}
static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd = NULL;
pgd = pgd_offset(mm, addr);
pmd = pmd_alloc(mm, pgd, addr);
return (pte_t *) pmd;
}
static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd = NULL;
pgd = pgd_offset(mm, addr);
pmd = pmd_offset(pgd, addr);
return (pte_t *) pmd;
}
#define mk_pte_huge(entry) {pte_val(entry) |= (_PAGE_PRESENT | _PAGE_PSE);}
static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struct page *page, pte_t * page_table, int write_access)
{
pte_t entry;
mm->rss += (HPAGE_SIZE / PAGE_SIZE);
if (write_access) {
entry =
pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
} else
entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
entry = pte_mkyoung(entry);
mk_pte_huge(entry);
set_pte(page_table, entry);
}
int
copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
struct vm_area_struct *vma)
{
pte_t *src_pte, *dst_pte, entry;
struct page *ptepage;
unsigned long addr = vma->vm_start;
unsigned long end = vma->vm_end;
while (addr < end) {
dst_pte = huge_pte_alloc(dst, addr);
if (!dst_pte)
goto nomem;
src_pte = huge_pte_offset(src, addr);
entry = *src_pte;
ptepage = pte_page(entry);
get_page(ptepage);
set_pte(dst_pte, entry);
dst->rss += (HPAGE_SIZE / PAGE_SIZE);
addr += HPAGE_SIZE;
}
return 0;
nomem:
return -ENOMEM;
}
int
follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
struct page **pages, struct vm_area_struct **vmas,
unsigned long *st, int *length, int i)
{
pte_t *ptep, pte;
unsigned long start = *st;
unsigned long pstart;
int len = *length;
struct page *page;
do {
pstart = start;
ptep = huge_pte_offset(mm, start);
pte = *ptep;
back1:
page = pte_page(pte);
if (pages) {
page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT);
pages[i] = page;
}
if (vmas)
vmas[i] = vma;
i++;
len--;
start += PAGE_SIZE;
if (((start & HPAGE_MASK) == pstart) && len &&
(start < vma->vm_end))
goto back1;
} while (len && start < vma->vm_end);
*length = len;
*st = start;
return i;
}
void free_huge_page(struct page *page)
{
BUG_ON(page_count(page));
BUG_ON(page->mapping);
INIT_LIST_HEAD(&page->list);
spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist);
htlbpagemem++;
spin_unlock(&htlbpage_lock);
}
void huge_page_release(struct page *page)
{
if (!put_page_testzero(page))
return;
free_huge_page(page);
}
void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
pte_t *pte;
struct page *page;
BUG_ON(start & (HPAGE_SIZE - 1));
BUG_ON(end & (HPAGE_SIZE - 1));
spin_lock(&htlbpage_lock);
spin_unlock(&htlbpage_lock);
for (address = start; address < end; address += HPAGE_SIZE) {
pte = huge_pte_offset(mm, address);
page = pte_page(*pte);
huge_page_release(page);
pte_clear(pte);
}
mm->rss -= (end - start) >> PAGE_SHIFT;
flush_tlb_range(vma, start, end);
}
void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long length)
{
struct mm_struct *mm = vma->vm_mm;
spin_lock(&mm->page_table_lock);
unmap_hugepage_range(vma, start, start + length);
spin_unlock(&mm->page_table_lock);
}
int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
{
struct mm_struct *mm = current->mm;
unsigned long addr;
int ret = 0;
BUG_ON(vma->vm_start & ~HPAGE_MASK);
BUG_ON(vma->vm_end & ~HPAGE_MASK);
spin_lock(&mm->page_table_lock);
for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
unsigned long idx;
pte_t *pte = huge_pte_alloc(mm, addr);
struct page *page;
if (!pte) {
ret = -ENOMEM;
goto out;
}
if (!pte_none(*pte))
continue;
idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
page = find_get_page(mapping, idx);
if (!page) {
page = alloc_hugetlb_page();
if (!page) {
ret = -ENOMEM;
goto out;
}
add_to_page_cache(page, mapping, idx);
unlock_page(page);
}
set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
}
out:
spin_unlock(&mm->page_table_lock);
return ret;
}
int set_hugetlb_mem_size(int count)
{
int j, lcount;
struct page *page, *map;
extern long htlbzone_pages;
extern struct list_head htlbpage_freelist;
if (count < 0)
lcount = count;
else
lcount = count - htlbzone_pages;
if (lcount > 0) { /* Increase the mem size. */
while (lcount--) {
page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
if (page == NULL)
break;
map = page;
for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
SetPageReserved(map);
map++;
}
spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist);
htlbpagemem++;
htlbzone_pages++;
spin_unlock(&htlbpage_lock);
}
return (int) htlbzone_pages;
}
/* Shrink the memory size. */
while (lcount++) {
page = alloc_hugetlb_page();
if (page == NULL)
break;
spin_lock(&htlbpage_lock);
htlbzone_pages--;
spin_unlock(&htlbpage_lock);
map = page;
for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
1 << PG_private | 1<< PG_writeback);
set_page_count(map, 0);
map++;
}
set_page_count(page, 1);
__free_pages(page, HUGETLB_PAGE_ORDER);
}
return (int) htlbzone_pages;
}
/* This will likely not work because of fragmentation. */
int hugetlb_sysctl_handler(ctl_table *table, int write, struct file *file, void *buffer, size_t *length)
{
proc_dointvec(table, write, file, buffer, length);
htlbpage_max = set_hugetlb_mem_size(htlbpage_max);
return 0;
}
static int __init hugetlb_setup(char *s)
{
if (sscanf(s, "%d", &htlbpage_max) <= 0)
htlbpage_max = 0;
return 1;
}
__setup("hugepages=", hugetlb_setup);
static int __init hugetlb_init(void)
{
int i, j;
struct page *page;
for (i = 0; i < htlbpage_max; ++i) {
page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
if (!page)
break;
for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j)
SetPageReserved(&page[j]);
spin_lock(&htlbpage_lock);
list_add(&page->list, &htlbpage_freelist);
spin_unlock(&htlbpage_lock);
}
htlbpage_max = htlbpagemem = htlbzone_pages = i;
printk("Total HugeTLB memory allocated, %ld\n", htlbpagemem);
return 0;
}
module_init(hugetlb_init);
int hugetlb_report_meminfo(char *buf)
{
return sprintf(buf,
"HugePages_Total: %5lu\n"
"HugePages_Free: %5lu\n"
"Hugepagesize: %5lu kB\n",
htlbzone_pages,
htlbpagemem,
HPAGE_SIZE/1024);
}
static struct page * hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int unused)
{
BUG();
return NULL;
}
struct vm_operations_struct hugetlb_vm_ops = {
.nopage = hugetlb_nopage,
};
int is_hugepage_mem_enough(size_t size)
{
if (size > (htlbpagemem << HPAGE_SHIFT))
return 0;
return 1;
}
......@@ -223,7 +223,8 @@ static void __init phys_pgd_init(pgd_t *pgd, unsigned long address, unsigned lon
set_pmd(pmd, __pmd(0));
break;
}
pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
pe = _PAGE_NX|_PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
pe &= __supported_pte_mask;
set_pmd(pmd, __pmd(pe));
}
unmap_low_page(map);
......
......@@ -10,32 +10,38 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
static struct vm_struct * modvmlist = NULL;
void module_unmap (void * addr)
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
void module_free(struct module *mod, void *module_region)
{
struct vm_struct **p, *tmp;
int i;
unsigned long addr = (unsigned long)module_region;
if (!addr)
return;
if ((PAGE_SIZE-1) & (unsigned long) addr) {
printk("Trying to unmap module with bad address (%p)\n", addr);
if ((PAGE_SIZE-1) & addr) {
printk("Trying to unmap module with bad address (%lx)\n", addr);
return;
}
for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
write_lock(&vmlist_lock);
for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
if ((unsigned long)tmp->addr == addr) {
*p = tmp->next;
write_unlock(&vmlist_lock);
goto found;
}
}
printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
write_unlock(&vmlist_lock);
printk("Trying to unmap nonexistent module vm area (%lx)\n", addr);
return;
found:
unmap_vm_area(tmp);
......@@ -49,29 +55,31 @@ void module_unmap (void * addr)
kfree(tmp);
}
void * module_map (unsigned long size)
void * module_alloc (unsigned long size)
{
struct vm_struct **p, *tmp, *area;
struct page **pages;
void * addr;
unsigned int nr_pages, array_size, i;
size = PAGE_ALIGN(size);
if (!size || size > MODULES_LEN)
if (!size)
return NULL;
size = PAGE_ALIGN(size);
if (size > MODULES_LEN)
return ERR_PTR(-ENOMEM);
addr = (void *) MODULES_VADDR;
for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
if ((unsigned long) addr + size >= MODULES_END)
return NULL;
return ERR_PTR(-ENOMEM);
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
return ERR_PTR(-ENOMEM);
area->size = size + PAGE_SIZE;
area->addr = addr;
area->next = *p;
......@@ -96,11 +104,12 @@ void * module_map (unsigned long size)
goto fail;
}
if (map_vm_area(area, PAGE_KERNEL, &pages)) {
if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages)) {
unmap_vm_area(area);
goto fail;
}
memset(area->addr, 0, size);
return area->addr;
fail:
......@@ -113,6 +122,6 @@ void * module_map (unsigned long size)
}
kfree(area);
return NULL;
return ERR_PTR(-ENOMEM);
}
......@@ -94,6 +94,11 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
}
}
void __devinit
pcibios_fixup_pbus_ranges (struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
}
/*
* Called after each bus is probed, but before its children
* are examined.
......
......@@ -151,30 +151,7 @@ static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigne
pci_write_config_byte(router, reg, x);
}
/*
* ALI pirq entries are damn ugly, and completely undocumented.
* This has been figured out from pirq tables, and it's not a pretty
* picture.
*/
static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
return irqmap[read_config_nybble(router, 0x48, pirq-1)];
}
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
unsigned int val = irqmap[irq];
if (val) {
write_config_nybble(router, 0x48, pirq-1, val);
return 1;
}
return 0;
}
#if 0 /* enable when pci ids ae known */
/*
* The VIA pirq rules are nibble-based, like ALI,
* but without the ugly irq number munging.
......@@ -296,6 +273,8 @@ static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i
return 1;
}
#endif
/* Support for AMD756 PCI IRQ Routing
* Jhon H. Caicedo <jhcaiced@osso.org.co>
* Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
......@@ -529,7 +508,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
return 1;
}
static void __init pcibios_fixup_irqs(void)
void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev;
u8 pin;
......@@ -641,7 +620,6 @@ int pirq_enable_irq(struct pci_dev *dev)
u8 pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
char *msg;
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.\n",
'A' + pin - 1, dev->slot_name);
}
......
......@@ -26,6 +26,7 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
. = ALIGN(64);
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
......@@ -79,6 +80,11 @@ SECTIONS
. = ALIGN(4096);
.data.boot_pgt : { *(.data.boot_pgt) }
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.init.text : { *(.init.text) }
......@@ -87,6 +93,9 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
__start___param = .;
__param : { *(__param) }
__stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
......@@ -105,6 +114,12 @@ SECTIONS
. = ALIGN(4096);
__init_end = .;
. = ALIGN(4096);
__nosave_begin = .;
.data_nosave : { *(.data.nosave) }
. = ALIGN(4096);
__nosave_end = .;
_end = . ;
/* Sections to be discarded */
......
......@@ -89,7 +89,7 @@ static __inline__ void __clear_bit(int nr, volatile void * addr)
/**
* __change_bit - Toggle a bit in memory
* @nr: the bit to set
* @nr: the bit to change
* @addr: the address to start counting from
*
* Unlike change_bit(), this function is non-atomic and may be reordered.
......@@ -106,7 +106,7 @@ static __inline__ void __change_bit(int nr, volatile void * addr)
/**
* change_bit - Toggle a bit in memory
* @nr: Bit to clear
* @nr: Bit to change
* @addr: Address to start counting from
*
* change_bit() is atomic and may not be reordered.
......@@ -162,7 +162,7 @@ static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
/**
* test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to set
* @nr: Bit to clear
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
......@@ -181,7 +181,7 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
/**
* __test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to set
* @nr: Bit to clear
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
......@@ -213,7 +213,7 @@ static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
/**
* test_and_change_bit - Change a bit and return its new value
* @nr: Bit to set
* @nr: Bit to change
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
......@@ -260,6 +260,8 @@ static __inline__ int variable_test_bit(int nr, volatile void * addr)
constant_test_bit((nr),(addr)) : \
variable_test_bit((nr),(addr)))
#undef ADDR
/**
* find_first_zero_bit - find the first zero bit in a memory region
* @addr: The address to start the search at
......
......@@ -29,6 +29,7 @@
#define RSP 152
#define SS 160
#define ARGOFFSET R11
#define SWFRAME ORIG_RAX
.macro SAVE_ARGS addskip=0,norcx=0
subq $9*8+\addskip,%rsp
......@@ -47,8 +48,11 @@
.endm
#define ARG_SKIP 9*8
.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0
.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0
.if \skipr11
.else
movq (%rsp),%r11
.endif
movq 1*8(%rsp),%r10
movq 2*8(%rsp),%r9
movq 3*8(%rsp),%r8
......
#ifndef _ASM_X86_64_COMPAT_H
#define _ASM_X86_64_COMPAT_H
/*
* Architecture specific compatibility types
*/
#include <linux/types.h>
#define COMPAT_USER_HZ 100
typedef u32 compat_size_t;
typedef s32 compat_ssize_t;
typedef s32 compat_time_t;
typedef s32 compat_suseconds_t;
typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
typedef u16 compat_uid_t;
typedef u16 compat_gid_t;
typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u16 compat_dev_t;
typedef s32 compat_off_t;
typedef u16 compat_nlink_t;
struct compat_timespec {
compat_time_t tv_sec;
s32 tv_nsec;
};
struct compat_timeval {
compat_time_t tv_sec;
s32 tv_usec;
};
struct compat_stat {
compat_dev_t st_dev;
u16 __pad1;
compat_ino_t st_ino;
compat_mode_t st_mode;
compat_nlink_t st_nlink;
compat_uid_t st_uid;
compat_gid_t st_gid;
compat_dev_t st_rdev;
u16 __pad2;
u32 st_size;
u32 st_blksize;
u32 st_blocks;
u32 st_atime;
u32 st_atime_nsec;
u32 st_mtime;
u32 st_mtime_nsec;
u32 st_ctime;
u32 st_ctime_nsec;
u32 __unused4;
u32 __unused5;
};
#endif /* _ASM_X86_64_COMPAT_H */
......@@ -165,31 +165,14 @@ static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
# error update this code.
#endif
static inline u64 load_TLS(struct thread_struct *t, int cpu)
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
u64 *p, old, new, change;
union u {
struct desc_struct d;
u64 i;
};
change = 0;
/* check assembly! */
#define C(i) \
p = ((u64 *)cpu_gdt_table[cpu]) + GDT_ENTRY_TLS_MIN + i; \
old = *p; \
new = t->tls_array[i]; \
change |= old - new; \
*p = new;
C(0); C(1); C(2);
return change;
u64 *gdt = (u64 *)(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN);
gdt[0] = t->tls_array[0];
gdt[1] = t->tls_array[1];
gdt[2] = t->tls_array[2];
}
#undef C
/*
* load one particular LDT into the current CPU
*/
......
......@@ -7,6 +7,7 @@
#include <asm/ptrace.h>
#include <asm/user.h>
#include <asm/processor.h>
typedef unsigned long elf_greg_t;
......@@ -14,7 +15,6 @@ typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
typedef struct user_fxsr_struct elf_fpxregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
......@@ -123,6 +123,17 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
extern void set_personality_64bit(void);
#define SET_PERSONALITY(ex, ibcs2) set_personality_64bit()
extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
#ifdef CONFIG_SMP
extern void dump_smp_unlazy_fpu(void);
#define ELF_CORE_SYNC dump_smp_unlazy_fpu
#endif
#endif
#endif
......@@ -77,6 +77,9 @@ typedef struct {
#define hardirq_endlock() do { } while (0)
#define irq_enter() (preempt_count() += HARDIRQ_OFFSET)
#define nmi_enter() (irq_enter())
#define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET)
#if CONFIG_PREEMPT
# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
......
......@@ -43,6 +43,12 @@ static inline int need_signal_i387(struct task_struct *me)
save_init_fpu(tsk); \
} while (0)
#define unlazy_current_fpu() do { \
if (test_thread_flag(TIF_USEDFPU)) \
save_init_fpu(tsk); \
} while (0)
#define clear_fpu(tsk) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
asm volatile("fwait"); \
......@@ -64,12 +70,6 @@ extern int get_fpregs(struct user_i387_struct *buf,
extern int set_fpregs(struct task_struct *tsk,
struct user_i387_struct *buf);
/*
* FPU state for core dumps...
*/
extern int dump_fpu(struct pt_regs *regs,
struct user_i387_struct *fpu);
/*
* i387 state interaction
*/
......
......@@ -5,29 +5,18 @@
#ifdef CONFIG_IA32_EMULATION
#include <linux/compat.h>
/*
* 32 bit structures for IA32 support.
*/
/* 32bit compatibility types */
typedef unsigned int __kernel_size_t32;
typedef int __kernel_ssize_t32;
typedef int __kernel_ptrdiff_t32;
typedef int __kernel_time_t32;
typedef int __kernel_clock_t32;
typedef int __kernel_pid_t32;
typedef unsigned short __kernel_ipc_pid_t32;
typedef unsigned short __kernel_uid_t32;
typedef unsigned __kernel_uid32_t32;
typedef unsigned short __kernel_gid_t32;
typedef unsigned __kernel_gid32_t32;
typedef unsigned short __kernel_dev_t32;
typedef unsigned int __kernel_ino_t32;
typedef unsigned short __kernel_mode_t32;
typedef unsigned short __kernel_umode_t32;
typedef short __kernel_nlink_t32;
typedef int __kernel_daddr_t32;
typedef int __kernel_off_t32;
typedef unsigned int __kernel_caddr_t32;
typedef long __kernel_loff_t32;
typedef __kernel_fsid_t __kernel_fsid_t32;
......@@ -37,9 +26,9 @@ typedef __kernel_fsid_t __kernel_fsid_t32;
struct flock32 {
short l_type;
short l_whence;
__kernel_off_t32 l_start;
__kernel_off_t32 l_len;
__kernel_pid_t32 l_pid;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
......@@ -98,30 +87,6 @@ struct ucontext_ia32 {
sigset32_t uc_sigmask; /* mask last for extensibility */
};
struct stat32 {
unsigned short st_dev;
unsigned short __pad1;
unsigned int st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned short st_rdev;
unsigned short __pad2;
unsigned int st_size;
unsigned int st_blksize;
unsigned int st_blocks;
unsigned int st_atime;
unsigned int __unused1;
unsigned int st_mtime;
unsigned int __unused2;
unsigned int st_ctime;
unsigned int __unused3;
unsigned int __unused4;
unsigned int __unused5;
};
/* This matches struct stat64 in glibc2.2, hence the absolutely
* insane amounts of padding around dev_t's.
*/
......@@ -146,9 +111,12 @@ struct stat64 {
long long st_blocks;/* Number 512-byte blocks allocated. */
unsigned long long st_atime;
unsigned long long st_mtime;
unsigned long long st_ctime;
unsigned st_atime;
unsigned st_atime_nsec;
unsigned st_mtime;
unsigned st_mtime_nsec;
unsigned st_ctime;
unsigned st_ctime_nsec;
unsigned long long st_ino;
} __attribute__((packed));
......@@ -204,8 +172,8 @@ typedef struct siginfo32 {
unsigned int _pid; /* which child */
unsigned int _uid; /* sender's uid */
int _status; /* exit code */
__kernel_clock_t32 _utime;
__kernel_clock_t32 _stime;
compat_clock_t _utime;
compat_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
......@@ -224,7 +192,7 @@ typedef struct siginfo32 {
struct ustat32 {
__u32 f_tfree;
__kernel_ino_t32 f_tinode;
compat_ino_t f_tinode;
char f_fname[6];
char f_fpack[6];
};
......@@ -234,6 +202,8 @@ struct iovec32 {
int iov_len;
};
#define IA32_PAGE_OFFSET 0xffff0000
#define IA32_STACK_TOP IA32_PAGE_OFFSET
#endif /* !CONFIG_IA32_SUPPORT */
......
......@@ -6,6 +6,7 @@
* this is for the kernel only.
*/
#define __NR_ia32_restart_syscall 0
#define __NR_ia32_exit 1
#define __NR_ia32_fork 2
#define __NR_ia32_read 3
......@@ -259,7 +260,13 @@
#define __NR_ia32_alloc_hugepages 250
#define __NR_ia32_free_hugepages 251
#define __NR_ia32_exit_group 252
#define __NR_ia32_lookup_dcookie 253
#define __NR_ia32_sys_epoll_create 254
#define __NR_ia32_sys_epoll_ctl 255
#define __NR_ia32_sys_epoll_wait 256
#define __NR_ia32_remap_file_pages 257
#define __NR_ia32_set_tid_address 258
#define IA32_NR_syscalls 260 /* must be > than biggest syscall! */
#define IA32_NR_syscalls 265 /* must be > than biggest syscall! */
#endif /* _ASM_X86_64_IA32_UNISTD_H_ */
......@@ -70,6 +70,7 @@ static __inline__ void ide_init_default_hwifs(void)
int index;
for(index = 0; index < MAX_HWIFS; index++) {
memset(&hw, 0, sizeof hw);
ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
hw.irq = ide_default_irq(ide_default_io_base(index));
ide_register_hw(&hw, NULL);
......
......@@ -178,19 +178,23 @@ extern void iounmap(void *addr);
#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
#define readq(addr) (*(volatile unsigned long *) __io_virt(addr))
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
#define __raw_readq readq
#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
#define writeq(b,addr) (*(volatile unsigned long *) __io_virt(addr) = (b))
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
#define __raw_writeq writeq
void *memcpy_fromio(void*,void*,unsigned);
void *memcpy_toio(void*,void*,unsigned);
void *memcpy_fromio(void*,const void*,unsigned);
void *memcpy_toio(void*,const void*,unsigned);
#define memset_io(a,b,c) memset(__io_virt(a),(b),(c))
/*
......@@ -215,7 +219,7 @@ void *memcpy_toio(void*,void*,unsigned);
/*
* Again, i386 does not require mem IO specific function.
* Again, x86-64 does not require mem IO specific function.
*/
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
......
......@@ -155,6 +155,8 @@ extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
#endif
extern int sis_apic_bug; /* dummy */
#else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0
......
......@@ -12,8 +12,8 @@
/*
* possibly do the LDT unload here?
*/
#define destroy_context(mm) do { } while(0)
int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void destroy_context(struct mm_struct *mm);
#ifdef CONFIG_SMP
......
#ifndef _ASM_X8664_MODULE_H
#define _ASM_X8664_MODULE_H
/*
* This file contains the x8664 architecture specific module code.
* Modules need to be mapped near the kernel code to allow 32bit relocations.
*/
struct mod_arch_specific {};
extern void *module_map(unsigned long);
extern void module_unmap(void *);
#define module_arch_init(x) (0)
#define arch_init_modules(x) do { } while (0)
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
#endif
......@@ -30,16 +30,16 @@
struct mtrr_sentry
{
__u64 base; /* Base address */
__u32 size; /* Size of region */
unsigned long base; /* Base address */
unsigned int size; /* Size of region */
unsigned int type; /* Type of region */
};
struct mtrr_gentry
{
__u64 base; /* Base address */
__u32 size; /* Size of region */
unsigned long base; /* Base address */
unsigned int regnum; /* Register number */
unsigned int size; /* Size of region */
unsigned int type; /* Type of region */
};
......@@ -65,49 +65,44 @@ struct mtrr_gentry
#define MTRR_TYPE_WRBACK 6
#define MTRR_NUM_TYPES 7
#ifdef MTRR_NEED_STRINGS
static char *mtrr_strings[MTRR_NUM_TYPES] =
{
"uncachable", /* 0 */
"write-combining", /* 1 */
"?", /* 2 */
"?", /* 3 */
"write-through", /* 4 */
"write-protect", /* 5 */
"write-back", /* 6 */
};
#endif
#ifdef __KERNEL__
extern char *mtrr_strings[MTRR_NUM_TYPES];
/* The following functions are for use by other drivers */
#ifdef CONFIG_MTRR
extern int mtrr_add (__u64 base, __u32 size, unsigned int type, char increment);
extern int mtrr_add_page (__u64 base, __u32 size, unsigned int type, char increment);
extern int mtrr_del (int reg, __u64 base, __u32 size);
extern int mtrr_del_page (int reg, __u64 base, __u32 size);
#else
static __inline__ int mtrr_add (__u64 base, __u32 size,
# ifdef CONFIG_MTRR
extern int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment);
extern int mtrr_add_page (unsigned long base, unsigned long size,
unsigned int type, char increment);
extern int mtrr_del (int reg, unsigned long base, unsigned long size);
extern int mtrr_del_page (int reg, unsigned long base, unsigned long size);
extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
# else
static __inline__ int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment)
{
return -ENODEV;
}
static __inline__ int mtrr_add_page (__u64 base, __u32 size,
static __inline__ int mtrr_add_page (unsigned long base, unsigned long size,
unsigned int type, char increment)
{
return -ENODEV;
}
static __inline__ int mtrr_del (int reg, __u64 base, __u32 size)
static __inline__ int mtrr_del (int reg, unsigned long base,
unsigned long size)
{
return -ENODEV;
}
static __inline__ int mtrr_del_page (int reg, __u64 base, __u32 size)
static __inline__ int mtrr_del_page (int reg, unsigned long base,
unsigned long size)
{
return -ENODEV;
}
#endif
extern void mtrr_init_cpu(int cpu);
static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;}
# endif
#endif
......
......@@ -16,6 +16,11 @@
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
......
......@@ -23,6 +23,7 @@ extern pgd_t level3_ident_pgt[512];
extern pmd_t level2_kernel_pgt[512];
extern pml4_t init_level4_pgt[];
extern pgd_t boot_vmalloc_pgt[];
extern unsigned long __supported_pte_mask;
#define swapper_pg_dir NULL
......@@ -97,7 +98,7 @@ static inline void set_pml4(pml4_t *dst, pml4_t val)
}
#define pgd_page(pgd) \
((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
((unsigned long) __va(pgd_val(pgd) & PHYSICAL_PAGE_MASK))
#define ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte, 0))
#define pte_same(a, b) ((a).pte == (b).pte)
......@@ -159,46 +160,53 @@ static inline void set_pml4(pml4_t *dst, pml4_t val)
#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_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
#define __PAGE_KERNEL_EXECUTABLE \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define __PAGE_KERNEL_NOCACHE \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
#define __PAGE_KERNEL_RO \
(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
#define __PAGE_KERNEL_VSYSCALL \
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL_LARGE \
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PSE)
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PSE | _PAGE_NX)
#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
#define PAGE_KERNEL_EXECUTABLE MAKE_GLOBAL(__PAGE_KERNEL_EXECUTABLE)
#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
#define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
/* xwr */
#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 __P100 PAGE_READONLY_EXEC
#define __P101 PAGE_READONLY_EXEC
#define __P110 PAGE_COPY_EXEC
#define __P111 PAGE_COPY_EXEC
#define __S000 PAGE_NONE
#define __S001 PAGE_READONLY
#define __S010 PAGE_SHARED
#define __S011 PAGE_SHARED
#define __S100 PAGE_READONLY
#define __S101 PAGE_READONLY
#define __S110 PAGE_SHARED
#define __S111 PAGE_SHARED
#define __S100 PAGE_READONLY_EXEC
#define __S101 PAGE_READONLY_EXEC
#define __S110 PAGE_SHARED_EXEC
#define __S111 PAGE_SHARED_EXEC
static inline unsigned long pgd_bad(pgd_t pgd)
{
......@@ -220,11 +228,12 @@ static inline unsigned long pgd_bad(pgd_t pgd)
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
pte_t pte;
pte_val(pte) = (page_nr << PAGE_SHIFT) | pgprot_val(pgprot);
pte_val(pte) = (page_nr << PAGE_SHIFT);
pte_val(pte) |= pgprot_val(pgprot);
pte_val(pte) &= __supported_pte_mask;
return pte;
}
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
......@@ -304,10 +313,6 @@ static inline pgd_t *current_pgd_offset_k(unsigned long address)
return __pgd_offset_k((pgd_t *)__va(addr), address);
}
#if 0 /* disabled because of confusing/wrong naming. */
#define __pgd_offset(address) pgd_index(address)
#endif
#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/* PMD - Level 2 access */
......
......@@ -68,6 +68,7 @@ struct cpuinfo_x86 {
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NUM 8
#define X86_VENDOR_UNKNOWN 0xff
extern struct cpuinfo_x86 boot_cpu_data;
......@@ -256,7 +257,7 @@ static inline void clear_in_cr4 (unsigned long mask)
* space during mmap's.
*/
#define TASK_UNMAPPED_32 0x40000000
#define TASK_UNMAPPED_64 (TASK_SIZE/3)
#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3)
#define TASK_UNMAPPED_BASE \
(test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)
......@@ -337,8 +338,8 @@ struct thread_struct {
#define EXCEPTION_STKSZ 1024
#define start_thread(regs,new_rip,new_rsp) do { \
__asm__("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0)); \
wrmsrl(MSR_KERNEL_GS_BASE, 0); \
asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0)); \
load_gs_index(0); \
(regs)->rip = (new_rip); \
(regs)->rsp = (new_rsp); \
write_pda(oldrsp, (new_rsp)); \
......@@ -358,7 +359,7 @@ extern void release_thread(struct task_struct *);
*/
extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern void release_segments(struct mm_struct * mm);
static inline void release_segments(struct mm_struct *mm) { }
/*
* Return saved PC of a blocked thread.
......@@ -389,4 +390,31 @@ extern inline void rep_nop(void)
#define cpu_relax() rep_nop()
/*
* NSC/Cyrix CPU configuration register indexes
*/
#define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1
#define CX86_CCR2 0xc2
#define CX86_CCR3 0xc3
#define CX86_CCR4 0xe8
#define CX86_CCR5 0xe9
#define CX86_CCR6 0xea
#define CX86_CCR7 0xeb
#define CX86_DIR0 0xfe
#define CX86_DIR1 0xff
#define CX86_ARR_BASE 0xc4
#define CX86_RCR_BASE 0xdc
/*
* NSC/Cyrix CPU indexed register access macros
*/
#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
#define setCx86(reg, data) do { \
outb((reg), 0x22); \
outb((data), 0x23); \
} while (0)
#endif /* __ASM_X86_64_PROCESSOR_H */
......@@ -4,8 +4,8 @@
struct scatterlist {
struct page *page;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
dma_addr_t dma_address;
};
#define ISA_DMA_THRESHOLD (0x00ffffff)
......
#ifndef SOCKET32_H
#define SOCKET32_H 1
#include <linux/compat.h>
/* XXX This really belongs in some header file... -DaveM */
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
16 for IP, 16 for IPX,
......@@ -11,14 +13,14 @@ struct msghdr32 {
u32 msg_name;
int msg_namelen;
u32 msg_iov;
__kernel_size_t32 msg_iovlen;
compat_size_t msg_iovlen;
u32 msg_control;
__kernel_size_t32 msg_controllen;
compat_size_t msg_controllen;
unsigned msg_flags;
};
struct cmsghdr32 {
__kernel_size_t32 cmsg_len;
compat_size_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
......
#ifndef SUSPEND_H
#define SUSPEND_H 1
/*
* Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
* Based on code
* Copyright 2001 Patrick Mochel <mochel@osdl.org>
*/
#include <asm/desc.h>
#include <asm/i387.h>
/* dummy for now */
static inline void
arch_prepare_suspend(void)
{
}
/* image of the saved processor state */
struct saved_context {
u16 ds, es, fs, gs, ss;
unsigned long gs_base, fs_base;
unsigned long cr0, cr2, cr3, cr4;
u16 gdt_pad;
u16 gdt_limit;
unsigned long gdt_base;
u16 idt_pad;
u16 idt_limit;
unsigned long idt_base;
u16 ldt;
u16 tss;
unsigned long tr;
unsigned long safety;
unsigned long return_address;
unsigned long eflags;
} __attribute__((packed));
/* We'll access these from assembly, so we'd better have them outside struct */
extern unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx;
extern unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi;
extern unsigned long saved_context_r08, saved_context_r09, saved_context_r10, saved_context_r11;
extern unsigned long saved_context_r12, saved_context_r13, saved_context_r14, saved_context_r15;
extern unsigned long saved_context_eflags;
#define loaddebug(thread,register) \
__asm__("movq %0,%%db" #register \
: /* no output */ \
:"r" ((thread)->debugreg[register]))
extern void fix_processor_context(void);
extern void do_magic(int resume);
#ifdef CONFIG_ACPI_SLEEP
extern unsigned long saved_eip;
extern unsigned long saved_esp;
extern unsigned long saved_ebp;
extern unsigned long saved_ebx;
extern unsigned long saved_esi;
extern unsigned long saved_edi;
static inline void acpi_save_register_state(unsigned long return_point)
{
/* FIXME: This is probably no longer correct: we need to save all caller-saved registers */
}
#define acpi_restore_register_state() do {} while (0)
/* routines for saving/restoring kernel state */
extern int acpi_save_state_mem(void);
extern int acpi_save_state_disk(void);
#endif
......@@ -19,8 +19,25 @@
#define __PUSH(x) "pushq %%" __STR(x) "\n\t"
#define __POP(x) "popq %%" __STR(x) "\n\t"
/* frame pointer must be last for get_wchan */
struct save_context_frame {
unsigned long rbp;
unsigned long rbx;
unsigned long rcx;
unsigned long rdx;
unsigned long rsi;
unsigned long rdi;
unsigned long rax;
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
};
/* frame pointer must be last for get_wchan */
/* It would be more efficient to let the compiler clobber most of these registers.
Clobbering all is not possible because that lets reload freak out. Even just
clobbering six generates wrong code with gcc 3.1 for me so do it this way for now.
......@@ -44,10 +61,11 @@
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%[prevrsp]\n\t" \
"movq %[nextrsp],%%rsp\n\t" \
"movq $1f,%[prevrip]\n\t" \
"movq $thread_return,%[prevrip]\n\t" \
"pushq %[nextrip]\n\t" \
"jmp __switch_to\n\t" \
"1:\n\t" \
".globl thread_return\n" \
"thread_return:\n\t" \
RESTORE_CONTEXT \
:[prevrsp] "=m" (prev->thread.rsp), \
[prevrip] "=m" (prev->thread.rip) \
......@@ -88,25 +106,31 @@ extern void load_gs_index(unsigned);
* Clear and set 'TS' bit respectively
*/
#define clts() __asm__ __volatile__ ("clts")
#define read_cr0() ({ \
unsigned long __dummy; \
__asm__( \
"movq %%cr0,%0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr0(x) \
__asm__("movq %0,%%cr0": :"r" (x));
#define read_cr4() ({ \
unsigned long __dummy; \
__asm__( \
"movq %%cr4,%0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr4(x) \
__asm__("movq %0,%%cr4": :"r" (x));
static inline unsigned long read_cr0(void)
{
unsigned long cr0;
asm volatile("movq %%cr0,%0" : "=r" (cr0));
return cr0;
}
static inline void write_cr0(unsigned long val)
{
asm volatile("movq %0,%%cr0" :: "r" (val));
}
static inline unsigned long read_cr4(void)
{
unsigned long cr4;
asm("movq %%cr4,%0" : "=r" (cr4));
return cr4;
}
static inline void write_cr4(unsigned long val)
{
asm volatile("movq %0,%%cr4" :: "r" (val));
}
#define stts() write_cr0(8 | read_cr0())
#define wbinvd() \
......@@ -210,7 +234,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
......
......@@ -29,6 +29,7 @@ struct thread_info {
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
};
#endif
......@@ -46,6 +47,9 @@ struct thread_info {
.cpu = 0, \
.preempt_count = 1, \
.addr_limit = KERNEL_DS, \
.restart_block = { \
.fn = do_no_restart_syscall, \
}, \
}
#define init_thread_info (init_thread_union.thread_info)
......
......@@ -399,15 +399,15 @@ __SYSCALL(__NR_iopl, stub_iopl)
__SYSCALL(__NR_ioperm, sys_ioperm)
#define __NR_create_module 174
__SYSCALL(__NR_create_module, sys_create_module)
__SYSCALL(__NR_create_module, sys_ni_syscall)
#define __NR_init_module 175
__SYSCALL(__NR_init_module, sys_init_module)
#define __NR_delete_module 176
__SYSCALL(__NR_delete_module, sys_delete_module)
#define __NR_get_kernel_syms 177
__SYSCALL(__NR_get_kernel_syms, sys_get_kernel_syms)
__SYSCALL(__NR_get_kernel_syms, sys_ni_syscall)
#define __NR_query_module 178
__SYSCALL(__NR_query_module, sys_query_module)
__SYSCALL(__NR_query_module, sys_ni_syscall)
#define __NR_quotactl 179
__SYSCALL(__NR_quotactl, sys_quotactl)
......@@ -426,7 +426,8 @@ __SYSCALL(__NR_afs_syscall, sys_ni_syscall)
#define __NR_tuxcall 184 /* reserved for tux */
__SYSCALL(__NR_tuxcall, sys_ni_syscall)
/* 165 currently unused */
#define __NR_security 185
__SYSCALL(__NR_security, sys_ni_syscall)
#define __NR_gettid 186
__SYSCALL(__NR_gettid, sys_gettid)
......@@ -483,8 +484,24 @@ __SYSCALL(__NR_io_cancel, sys_io_cancel)
__SYSCALL(__NR_get_thread_area, sys_get_thread_area)
#define __NR_lookup_dcookie 212
__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
#define __NR_syscall_max __NR_lookup_dcookie
#define __NR_epoll_create 213
__SYSCALL(__NR_epoll_create, sys_epoll_create)
#define __NR_epoll_ctl 214
__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
#define __NR_epoll_wait 215
__SYSCALL(__NR_epoll_wait, sys_epoll_wait)
#define __NR_remap_file_pages 216
__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
#define __NR_getdents64 217
__SYSCALL(__NR_getdents64, sys_getdents64)
#define __NR_set_tid_address 218
__SYSCALL(__NR_set_tid_address, sys_set_tid_address)
#define __NR_restart_syscall 219
__SYSCALL(__NR_restart_syscall, sys_restart_syscall)
#define __NR_semtimedop 220
__SYSCALL(__NR_semtimedop, sys_semtimedop)
#define __NR_syscall_max __NR_semtimedop
#ifndef __NO_STUBS
/* user-visible error numbers are in the range -1 - -4095 */
......@@ -605,7 +622,7 @@ static inline pid_t setsid(void)
return sys_setsid();
}
extern ssize_t sys_write(unsigned int, char *, size_t);
long sys_write(int fd, const char *buf, size_t size);
static inline ssize_t write(unsigned int fd, char * buf, size_t count)
{
return sys_write(fd, buf, count);
......@@ -651,7 +668,7 @@ extern inline long exit(int error_code)
}
struct rusage;
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr,
long sys_wait4(pid_t pid,unsigned int * stat_addr,
int options, struct rusage * ru);
static inline pid_t waitpid(int pid, int * wait_stat, int flags)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment