Commit 3428c8d1 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86-64 updates for 2.5.43

This fixes a few files that got lost with the last merge and merges
with 2.5.43/i386.  Only changes architecture specific files.

It depends on one other patch (for linux/ioctl32.h) which I'm sending
separately.

Changes:
- Include missing files (pageattr.c) and Makefile changes
- Update IA32 subsystem. Various small fixes and a big merge
  with sparc64.
- Change HZ to 1000
- Merge some of the 2.5.43/i386 profiling changes. No full oprofile yet.
- Fix many warnings
- Update defconfig
- Various other smaller cleanups and bugfixes.
parent 5a7728c6
...@@ -435,6 +435,14 @@ CONFIG_X86_CPUID ...@@ -435,6 +435,14 @@ CONFIG_X86_CPUID
with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
/dev/cpu/31/cpuid. /dev/cpu/31/cpuid.
CONFIG_NR_CPUS
This allows you to specify the maximum number of CPUs which this
kernel will support. The maximum supported value is 32 and the
minimum value which makes sense is 2.
This is purely to save memory - each supported CPU adds
approximately eight kilobytes to the kernel image.
CONFIG_PREEMPT CONFIG_PREEMPT
This option reduces the latency of the kernel when reacting to This option reduces the latency of the kernel when reacting to
real-time or interactive events by allowing a low priority process to real-time or interactive events by allowing a low priority process to
...@@ -487,10 +495,6 @@ CONFIG_CHECKING ...@@ -487,10 +495,6 @@ CONFIG_CHECKING
Enables some internal consistency checks for kernel debugging. Enables some internal consistency checks for kernel debugging.
You should normally say N. You should normally say N.
CONFIG_SIMNOW
Disable some time consuming optional things for slow CPU simulators.
Say N unless you're running on a slow simulator like Simics or SimNow.
CONFIG_EARLY_PRINTK CONFIG_EARLY_PRINTK
Write kernel log output directly into the VGA buffer. This is useful Write kernel log output directly into the VGA buffer. This is useful
for kernel debugging when your machine crashes very early before for kernel debugging when your machine crashes very early before
...@@ -499,13 +503,26 @@ CONFIG_EARLY_PRINTK ...@@ -499,13 +503,26 @@ CONFIG_EARLY_PRINTK
klogd/syslogd or the X server.You should normally N here, unless klogd/syslogd or the X server.You should normally N here, unless
you want to debug such a crash. you want to debug such a crash.
CONFIG_X86_MCE_NONFATAL CONFIG_KALLSYMS
Enabling this feature starts a timer that triggers every 5 seconds which Say Y here to let the kernel print out symbolic crash information and
will look at the machine check registers to see if anything happened. symbolic stack backtraces. This increases the size of the kernel
Non-fatal problems automatically get corrected (but still logged). somewhat, as all symbols have to be loaded into the kernel image.
Disable this if you don't want to see these messages.
Seeing the messages this option prints out may be indicative of dying hardware, CONFIG_INIT_DEBUG
or out-of-spec (ie, overclocked) hardware. Fill __init and __initdata at the end of boot. This is only for debugging.
This option only does something on hardware with Intel P6 style MCE.
(Pentium Pro and above, AMD Athlon/Duron) CONFIG_IA32_EMULATION
Include code to run 32bit programs under an 64bit kernel. You should likely
turn this on, unless you're 100% sure that you don't have any 32bit programs
left.
CONFIG_GART_IOMMU
Support the K8 IOMMU. Needed to run systems with more than 4GB of memory
properly with 32bit devices. You should probably turn this on.
The iommu can be turned off at runtime with the iommu=off parameter.
CONFIG_DUMMY_IOMMU
Don't use IOMMU code. This will cause problems when you have more than 4GB
of memory and any 32bit devices. Don't turn on unless you know what you
are doing.
...@@ -33,7 +33,7 @@ IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E ...@@ -33,7 +33,7 @@ IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E
export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
LD=$(CROSS_COMPILE)ld -m elf_x86_64 LDFLAGS := -m elf_x86_64
OBJCOPYFLAGS := -O binary -R .note -R .comment -S OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LDFLAGS_vmlinux := -e stext LDFLAGS_vmlinux := -e stext
...@@ -47,52 +47,39 @@ CFLAGS += -finline-limit=2000 ...@@ -47,52 +47,39 @@ CFLAGS += -finline-limit=2000
HEAD := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o HEAD := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
SUBDIRS += arch/x86_64/kernel arch/x86_64/mm arch/x86_64/lib libs-y += arch/x86_64/lib/
CORE_FILES := arch/x86_64/kernel/kernel.o $(CORE_FILES) core-y += arch/x86_64/kernel/ arch/x86_64/mm/
CORE_FILES += arch/x86_64/mm/mm.o core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
LIBS := $(TOPDIR)/arch/x86_64/lib/lib.a $(LIBS) drivers-$(CONFIG_PCI) += arch/x86_64/pci/
ifdef CONFIG_IA32_EMULATION
SUBDIRS += arch/x86_64/ia32
CORE_FILES += arch/x86_64/ia32/ia32.o
endif
ifdef CONFIG_PCI
SUBDIRS += arch/x86_64/pci
DRIVERS += arch/x86_64/pci/pci.o
endif
CORE_FILES += $(core-y)
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
makeboot = $(call descend,arch/x86_64/boot,$(1))
.PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \ .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
clean archclean archmrproper clean archclean archmrproper
bzImage: vmlinux BOOTIMAGE=arch/x86_64/boot/bzImage
@$(MAKEBOOT) bzImage zImage zlilo zdisk: BOOTIMAGE=arch/x86_64/boot/zImage
bzImage-padded: vmlinux zImage bzImage: vmlinux
@$(MAKEBOOT) bzImage-padded +@$(call makeboot,$(BOOTIMAGE))
tmp: compressed: zImage
@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
bzlilo: vmlinux zlilo bzlilo: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zlilo)
bzdisk: vmlinux zdisk bzdisk: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zdisk)
install: vmlinux install: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage install +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install)
archclean: archclean:
@$(MAKEBOOT) clean +@$(call makeboot,clean)
archmrproper: archmrproper:
prepare: include/asm-$(ARCH)/offset.h prepare: include/asm-$(ARCH)/offset.h
arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
......
...@@ -190,7 +190,7 @@ static void puts(const char *s) ...@@ -190,7 +190,7 @@ static void puts(const char *s)
outb_p(0xff & (pos >> 1), vidport+1); outb_p(0xff & (pos >> 1), vidport+1);
} }
void* memset(void* s, int c, size_t n) void* memset(void* s, int c, unsigned n)
{ {
int i; int i;
char *ss = (char*)s; char *ss = (char*)s;
...@@ -199,14 +199,13 @@ void* memset(void* s, int c, size_t n) ...@@ -199,14 +199,13 @@ void* memset(void* s, int c, size_t n)
return s; return s;
} }
void* memcpy(void* __dest, __const void* __src, void* memcpy(void* dest, const void* src, unsigned n)
size_t __n)
{ {
int i; int i;
char *d = (char *)__dest, *s = (char *)__src; char *d = (char *)dest, *s = (char *)src;
for (i=0;i<__n;i++) d[i] = s[i]; for (i=0;i<n;i++) d[i] = s[i];
return __dest; return dest;
} }
/* =========================================================================== /* ===========================================================================
......
...@@ -21,6 +21,7 @@ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n ...@@ -21,6 +21,7 @@ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
define_bool CONFIG_X86_CMPXCHG y define_bool CONFIG_X86_CMPXCHG y
define_bool CONFIG_EARLY_PRINTK y define_bool CONFIG_EARLY_PRINTK y
define_bool CONFIG_GENERIC_ISA_DMA y
source init/Config.in source init/Config.in
...@@ -54,11 +55,17 @@ if [ "$CONFIG_SMP" = "n" ]; then ...@@ -54,11 +55,17 @@ if [ "$CONFIG_SMP" = "n" ]; then
fi fi
if [ "$CONFIG_SMP" = "y" ]; then if [ "$CONFIG_SMP" = "y" ]; then
define_bool CONFIG_HAVE_DEC_LOCK y define_bool CONFIG_HAVE_DEC_LOCK y
# actually 64 maximum, but you need to fix the APIC code first
# to use clustered mode or whatever your big iron needs
int 'Maximum number of CPUs (2-8)' CONFIG_NR_CPUS 8 int 'Maximum number of CPUs (2-8)' CONFIG_NR_CPUS 8
fi fi
bool 'IOMMU support' CONFIG_GART_IOMMU
if [ "$CONFIG_GART_IOMMU" != "y" ]; then
define_bool CONFIG_DUMMY_IOMMU y
fi
define_bool CONFIG_X86_MCE y define_bool CONFIG_X86_MCE y
bool 'Check for non-fatal machine check errors' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE
endmenu endmenu
...@@ -108,22 +115,20 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC ...@@ -108,22 +115,20 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
bool 'IA32 Emulation' CONFIG_IA32_EMULATION bool 'IA32 Emulation' CONFIG_IA32_EMULATION
endmenu endmenu
source drivers/mtd/Config.in source drivers/mtd/Config.in
source drivers/parport/Config.in source drivers/parport/Config.in
#source drivers/pnp/Config.in
source drivers/block/Config.in source drivers/block/Config.in
source drivers/md/Config.in
mainmenu_option next_comment mainmenu_option next_comment
comment 'ATA/ATAPI/MFM/RLL support' comment 'ATA/ATAPI/MFM/RLL support'
tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE tristate 'ATA/ATAPI/MFM/RLL device support' CONFIG_IDE
if [ "$CONFIG_IDE" != "n" ]; then if [ "$CONFIG_IDE" != "n" ]; then
source drivers/ide/Config.in source drivers/ide/Config.in
...@@ -133,15 +138,19 @@ fi ...@@ -133,15 +138,19 @@ fi
endmenu endmenu
mainmenu_option next_comment mainmenu_option next_comment
comment 'SCSI support' comment 'SCSI device support'
tristate 'SCSI support' CONFIG_SCSI tristate 'SCSI device support' CONFIG_SCSI
if [ "$CONFIG_SCSI" != "n" ]; then if [ "$CONFIG_SCSI" != "n" ]; then
source drivers/scsi/Config.in source drivers/scsi/Config.in
fi fi
endmenu endmenu
source drivers/md/Config.in
source drivers/telephony/Config.in
source drivers/message/fusion/Config.in source drivers/message/fusion/Config.in
source drivers/ieee1394/Config.in source drivers/ieee1394/Config.in
...@@ -172,8 +181,6 @@ source net/irda/Config.in ...@@ -172,8 +181,6 @@ source net/irda/Config.in
source drivers/isdn/Config.in source drivers/isdn/Config.in
source drivers/telephony/Config.in
# no support for non IDE/SCSI cdroms as they were all ISA only # no support for non IDE/SCSI cdroms as they were all ISA only
# #
...@@ -224,6 +231,8 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then ...@@ -224,6 +231,8 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Additional run-time checks' CONFIG_CHECKING bool ' Additional run-time checks' CONFIG_CHECKING
bool ' Debug __init statements' CONFIG_INIT_DEBUG bool ' Debug __init statements' CONFIG_INIT_DEBUG
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
fi fi
endmenu endmenu
......
This diff is collapsed.
...@@ -25,7 +25,7 @@ struct elf_phdr; ...@@ -25,7 +25,7 @@ struct elf_phdr;
#define IA32_EMULATOR 1 #define IA32_EMULATOR 1
#define IA32_PAGE_OFFSET 0xE0000000 #define IA32_PAGE_OFFSET 0xffff0000
#define IA32_STACK_TOP IA32_PAGE_OFFSET #define IA32_STACK_TOP IA32_PAGE_OFFSET
#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) #define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000)
...@@ -216,13 +216,15 @@ static void elf32_init(struct pt_regs *regs) ...@@ -216,13 +216,15 @@ static void elf32_init(struct pt_regs *regs)
extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
int ia32_setup_arg_pages(struct linux_binprm *bprm) int setup_arg_pages(struct linux_binprm *bprm)
{ {
unsigned long stack_base; unsigned long stack_base;
struct vm_area_struct *mpnt; struct vm_area_struct *mpnt;
struct mm_struct *mm = current->mm;
int i; int i;
stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; stack_base = IA32_STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE;
mm->arg_start = bprm->p + stack_base;
bprm->p += stack_base; bprm->p += stack_base;
if (bprm->loader) if (bprm->loader)
...@@ -233,9 +235,14 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm) ...@@ -233,9 +235,14 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm)
if (!mpnt) if (!mpnt)
return -ENOMEM; return -ENOMEM;
down_write(&current->mm->mmap_sem); if (!vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
kmem_cache_free(vm_area_cachep, mpnt);
return -ENOMEM;
}
down_write(&mm->mmap_sem);
{ {
mpnt->vm_mm = current->mm; mpnt->vm_mm = mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = IA32_STACK_TOP; mpnt->vm_end = IA32_STACK_TOP;
mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_page_prot = PAGE_COPY;
...@@ -243,24 +250,25 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm) ...@@ -243,24 +250,25 @@ int ia32_setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_ops = NULL; mpnt->vm_ops = NULL;
mpnt->vm_pgoff = 0; mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL; mpnt->vm_file = NULL;
INIT_LIST_HEAD(&mpnt->shared);
mpnt->vm_private_data = (void *) 0; mpnt->vm_private_data = (void *) 0;
insert_vm_struct(current->mm, mpnt); insert_vm_struct(mm, mpnt);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
} }
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
struct page *page = bprm->page[i]; struct page *page = bprm->page[i];
if (page) { if (page) {
bprm->page[i] = NULL; bprm->page[i] = NULL;
current->mm->rss++;
put_dirty_page(current,page,stack_base); put_dirty_page(current,page,stack_base);
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
up_write(&current->mm->mmap_sem); up_write(&mm->mmap_sem);
return 0; return 0;
} }
static unsigned long static unsigned long
elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
{ {
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
* 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
* *
* $Id: ia32_signal.c,v 1.17 2002/03/21 14:16:32 ak Exp $ * $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
*/ */
#include <linux/sched.h> #include <linux/sched.h>
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
void signal_fault(struct pt_regs *regs, void *frame, char *where);
static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from) static int ia32_copy_siginfo_to_user(siginfo_t32 *to, siginfo_t *from)
{ {
...@@ -163,32 +164,38 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign ...@@ -163,32 +164,38 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign
regs->r ## x = reg; \ regs->r ## x = reg; \
} }
#define RELOAD_SEG(seg) \ #define RELOAD_SEG(seg,mask) \
{ unsigned int cur; \ { unsigned int cur; \
unsigned short pre; \ unsigned short pre; \
err |= __get_user(pre, &sc->seg); \ err |= __get_user(pre, &sc->seg); \
asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \ asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \
pre |= mask; \
if (pre != cur) loadsegment(seg,pre); } if (pre != cur) loadsegment(seg,pre); }
/* Reload fs and gs if they have changed in the signal handler. */ /* Reload fs and gs if they have changed in the signal handler.
This does not handle long fs/gs base changes in the handler, but
does not clobber them at least in the normal case. */
{ {
unsigned short gs; unsigned gs, oldgs;
err |= __get_user(gs, &sc->gs); err |= __get_user(gs, &sc->gs);
gs |= 3;
asm("movl %%gs,%0" : "=r" (oldgs));
if (gs != oldgs)
load_gs_index(gs); load_gs_index(gs);
} }
RELOAD_SEG(fs); RELOAD_SEG(fs,3);
RELOAD_SEG(ds); RELOAD_SEG(ds,3);
RELOAD_SEG(es); RELOAD_SEG(es,3);
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip); COPY(dx); COPY(cx); COPY(ip);
/* Don't touch extended registers */ /* Don't touch extended registers */
err |= __get_user(regs->cs, &sc->cs); err |= __get_user(regs->cs, &sc->cs);
regs->cs |= 2; regs->cs |= 3;
err |= __get_user(regs->ss, &sc->ss); err |= __get_user(regs->ss, &sc->ss);
regs->ss |= 2; regs->ss |= 3;
{ {
unsigned int tmpflags; unsigned int tmpflags;
...@@ -284,7 +291,7 @@ asmlinkage int sys32_rt_sigreturn(struct pt_regs regs) ...@@ -284,7 +291,7 @@ asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
return eax; return eax;
badframe: badframe:
signal_fault(&regs, frame, "32bit rt sigreturn"); signal_fault(&regs,frame,"32bit rt sigreturn");
return 0; return 0;
} }
...@@ -377,8 +384,9 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, ...@@ -377,8 +384,9 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
{ {
struct exec_domain *ed = current_thread_info()->exec_domain; struct exec_domain *ed = current_thread_info()->exec_domain;
err |= __put_user((ed
err |= __put_user((ed && ed->signal_invmap && sig < 32 && ed->signal_invmap
&& sig < 32
? ed->signal_invmap[sig] ? ed->signal_invmap[sig]
: sig), : sig),
&frame->sig); &frame->sig);
...@@ -435,7 +443,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, ...@@ -435,7 +443,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
give_sigsegv: give_sigsegv:
if (sig == SIGSEGV) if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL; ka->sa.sa_handler = SIG_DFL;
signal_fault(regs,frame,"32bit signal setup"); signal_fault(regs,frame,"32bit signal deliver");
} }
void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
...@@ -449,9 +457,12 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -449,9 +457,12 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
{ {
struct exec_domain *ed = current_thread_info()->exec_domain; struct exec_domain *ed = current_thread_info()->exec_domain;
err |= __put_user((ed && ed->signal_invmap && sig < 32 err |= __put_user((ed
&& ed->signal_invmap
&& sig < 32
? ed->signal_invmap[sig] ? ed->signal_invmap[sig]
: sig), : sig),
&frame->sig); &frame->sig);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
*/ */
ENTRY(ia32_cstar_target) ENTRY(ia32_cstar_target)
movq $-ENOSYS,%rax movq $-ENOSYS,%rax
sysret sysretl
/* /*
* Emulated IA32 system calls via int 0x80. * Emulated IA32 system calls via int 0x80.
...@@ -77,6 +77,7 @@ ia32_tracesys: ...@@ -77,6 +77,7 @@ ia32_tracesys:
jmp ia32_do_syscall jmp ia32_do_syscall
ia32_badsys: ia32_badsys:
movq $0,ORIG_RAX-ARGOFFSET(%rsp)
movq $-ENOSYS,RAX-ARGOFFSET(%rsp) movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
jmp int_ret_from_sys_call jmp int_ret_from_sys_call
...@@ -84,6 +85,10 @@ ni_syscall: ...@@ -84,6 +85,10 @@ ni_syscall:
movq %rax,%rdi movq %rax,%rdi
jmp sys32_ni_syscall jmp sys32_ni_syscall
quiet_ni_syscall:
movq $-ENOSYS,%rax
ret
.macro PTREGSCALL label, func .macro PTREGSCALL label, func
.globl \label .globl \label
\label: \label:
...@@ -229,7 +234,7 @@ ia32_sys_call_table: ...@@ -229,7 +234,7 @@ ia32_sys_call_table:
.quad stub32_iopl /* 110 */ .quad stub32_iopl /* 110 */
.quad sys_vhangup .quad sys_vhangup
.quad ni_syscall /* old "idle" system call */ .quad ni_syscall /* old "idle" system call */
.quad ni_syscall /* vm86old */ .quad sys32_vm86_warning /* vm86old */
.quad sys32_wait4 .quad sys32_wait4
.quad sys_swapoff /* 115 */ .quad sys_swapoff /* 115 */
.quad sys32_sysinfo .quad sys32_sysinfo
...@@ -238,7 +243,7 @@ ia32_sys_call_table: ...@@ -238,7 +243,7 @@ ia32_sys_call_table:
.quad stub32_sigreturn .quad stub32_sigreturn
.quad stub32_clone /* 120 */ .quad stub32_clone /* 120 */
.quad sys_setdomainname .quad sys_setdomainname
.quad sys32_newuname .quad sys_uname
.quad sys_modify_ldt .quad sys_modify_ldt
.quad sys32_adjtimex .quad sys32_adjtimex
.quad sys32_mprotect /* 125 */ .quad sys32_mprotect /* 125 */
...@@ -282,8 +287,8 @@ ia32_sys_call_table: ...@@ -282,8 +287,8 @@ ia32_sys_call_table:
.quad sys_mremap .quad sys_mremap
.quad sys_setresuid16 .quad sys_setresuid16
.quad sys_getresuid16 /* 165 */ .quad sys_getresuid16 /* 165 */
.quad ni_syscall /* vm86 */ .quad sys32_vm86_warning /* vm86 */
.quad ni_syscall /* query_module */ .quad quiet_ni_syscall /* query_module */
.quad sys_poll .quad sys_poll
.quad sys32_nfsservctl .quad sys32_nfsservctl
.quad sys_setresgid16 /* 170 */ .quad sys_setresgid16 /* 170 */
...@@ -368,7 +373,7 @@ ia32_sys_call_table: ...@@ -368,7 +373,7 @@ ia32_sys_call_table:
.quad sys_io_cancel .quad sys_io_cancel
.quad sys_ni_syscall /* 250 alloc_huge_pages */ .quad sys_ni_syscall /* 250 alloc_huge_pages */
.quad sys_ni_syscall /* free_huge_pages */ .quad sys_ni_syscall /* free_huge_pages */
.quad sys_ni_syscall /* exit_group */ .quad sys_exit_group /* exit_group */
ia32_syscall_end: ia32_syscall_end:
.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
.quad ni_syscall .quad ni_syscall
......
...@@ -264,6 +264,9 @@ semctl32 (int first, int second, int third, void *uptr) ...@@ -264,6 +264,9 @@ semctl32 (int first, int second, int third, void *uptr)
if (err2) if (err2)
err = -EFAULT; err = -EFAULT;
break; break;
default:
err = -EINVAL;
break;
} }
return err; return err;
} }
...@@ -284,7 +287,7 @@ do_sys32_msgsnd (int first, int second, int third, void *uptr) ...@@ -284,7 +287,7 @@ do_sys32_msgsnd (int first, int second, int third, void *uptr)
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
err = get_user(p->mtype, &up->mtype); err = get_user(p->mtype, &up->mtype);
err |= copy_from_user(p->mtext, &up->mtext, second); err |= (copy_from_user(p->mtext, &up->mtext, second) ? -EFAULT : 0);
if (err) if (err)
goto out; goto out;
old_fs = get_fs(); old_fs = get_fs();
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/sem.h> #include <linux/sem.h>
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/binfmts.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -56,6 +55,7 @@ ...@@ -56,6 +55,7 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/ipc.h> #include <linux/ipc.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/binfmts.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/aio_abi.h> #include <linux/aio_abi.h>
#include <asm/mman.h> #include <asm/mman.h>
...@@ -264,8 +264,11 @@ sys32_mmap(struct mmap_arg_struct *arg) ...@@ -264,8 +264,11 @@ sys32_mmap(struct mmap_arg_struct *arg)
if (!file) if (!file)
return -EBADF; return -EBADF;
} }
#if 0 /* reenable when noexec works */
if (a.prot & PROT_READ) if (a.prot & PROT_READ)
a.prot |= PROT_EXEC; a.prot |= PROT_EXEC;
#endif
a.flags |= MAP_32BIT; a.flags |= MAP_32BIT;
...@@ -275,8 +278,8 @@ sys32_mmap(struct mmap_arg_struct *arg) ...@@ -275,8 +278,8 @@ sys32_mmap(struct mmap_arg_struct *arg)
if (file) if (file)
fput(file); fput(file);
/* Should not happen */ /* Cannot wrap */
if (retval >= 0xFFFFFFFF && (long)retval > 0) { if (retval+a.len >= 0xFFFFFFFF && (long)retval > 0) {
do_munmap(mm, retval, a.len); do_munmap(mm, retval, a.len);
retval = -ENOMEM; retval = -ENOMEM;
} }
...@@ -964,22 +967,24 @@ sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) ...@@ -964,22 +967,24 @@ sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long); asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
struct iovec * static struct iovec *
get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type, int *errp)
{ {
int i; int i;
u32 buf, len; u32 buf, len;
struct iovec *ivp, *iov; struct iovec *ivp, *iov;
unsigned long totlen;
/* Get the "struct iovec" from user memory */ /* Get the "struct iovec" from user memory */
if (!count) if (!count)
return 0; return 0;
if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
return(struct iovec *)0;
if (count > UIO_MAXIOV) if (count > UIO_MAXIOV)
return(struct iovec *)0; return(struct iovec *)0;
if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
return(struct iovec *)0;
if (count > UIO_FASTIOV) { if (count > UIO_FASTIOV) {
*errp = -ENOMEM;
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
if (!iov) if (!iov)
return((struct iovec *)0); return((struct iovec *)0);
...@@ -987,24 +992,33 @@ get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) ...@@ -987,24 +992,33 @@ get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
iov = iov_buf; iov = iov_buf;
ivp = iov; ivp = iov;
totlen = 0;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (__get_user(len, &iov32->iov_len) || *errp = __get_user(len, &iov32->iov_len) |
__get_user(buf, &iov32->iov_base)) { __get_user(buf, &iov32->iov_base);
if (iov != iov_buf) if (*errp)
kfree(iov); goto error;
return((struct iovec *)0); *errp = verify_area(type, (void *)A(buf), len);
} if (*errp)
if (verify_area(type, (void *)A(buf), len)) { goto error;
if (iov != iov_buf) /* SuS checks: */
kfree(iov); *errp = -EINVAL;
return((struct iovec *)0); if ((int)len < 0)
} goto error;
if ((totlen += len) >= 0x7fffffff)
goto error;
ivp->iov_base = (void *)A(buf); ivp->iov_base = (void *)A(buf);
ivp->iov_len = (__kernel_size_t)len; ivp->iov_len = (__kernel_size_t)len;
iov32++; iov32++;
ivp++; ivp++;
} }
*errp = 0;
return(iov); return(iov);
error:
if (iov != iov_buf)
kfree(iov);
return NULL;
} }
asmlinkage long asmlinkage long
...@@ -1015,8 +1029,8 @@ sys32_readv(int fd, struct iovec32 *vector, u32 count) ...@@ -1015,8 +1029,8 @@ sys32_readv(int fd, struct iovec32 *vector, u32 count)
int ret; int ret;
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0) if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE, &ret)) == NULL)
return -EFAULT; return ret;
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
ret = sys_readv(fd, iov, count); ret = sys_readv(fd, iov, count);
set_fs(old_fs); set_fs(old_fs);
...@@ -1033,8 +1047,8 @@ sys32_writev(int fd, struct iovec32 *vector, u32 count) ...@@ -1033,8 +1047,8 @@ sys32_writev(int fd, struct iovec32 *vector, u32 count)
int ret; int ret;
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0) if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ, &ret)) == NULL)
return -EFAULT; return ret;
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
ret = sys_writev(fd, iov, count); ret = sys_writev(fd, iov, count);
set_fs(old_fs); set_fs(old_fs);
...@@ -1121,7 +1135,7 @@ sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) ...@@ -1121,7 +1135,7 @@ sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
/* /*
* sys_time() can be implemented in user-level using * sys_time() can be implemented in user-level using
* sys_gettimeofday(). IA64 did this but i386 Linux did not * sys_gettimeofday(). x86-64 did this but i386 Linux did not
* so we have to implement this system call here. * so we have to implement this system call here.
*/ */
asmlinkage long sys32_time(int * tloc) asmlinkage long sys32_time(int * tloc)
...@@ -1288,6 +1302,39 @@ static inline int put_flock(struct flock *kfl, struct flock32 *ufl) ...@@ -1288,6 +1302,39 @@ static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
} }
extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case F_GETLK:
case F_SETLK:
case F_SETLKW:
{
struct flock f;
mm_segment_t old_fs;
long ret;
if (get_flock(&f, (struct flock32 *)arg))
return -EFAULT;
old_fs = get_fs(); set_fs (KERNEL_DS);
ret = sys_fcntl(fd, cmd, (unsigned long)&f);
set_fs (old_fs);
if (ret) return ret;
if (put_flock(&f, (struct flock32 *)arg))
return -EFAULT;
return 0;
}
case F_GETLK64:
case F_SETLK64:
case F_SETLKW64:
return sys32_fcntl64(fd,cmd,arg);
default:
return sys_fcntl(fd, cmd, (unsigned long)arg);
}
}
static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64) static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
{ {
...@@ -1319,40 +1366,34 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a ...@@ -1319,40 +1366,34 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
{ {
struct flock fl64; struct flock fl64;
mm_segment_t oldfs = get_fs(); mm_segment_t oldfs = get_fs();
int ret = 0, origcmd; int ret = 0;
unsigned long origarg; int oldcmd = cmd;
unsigned long oldarg = arg;
origcmd = cmd;
origarg = arg;
switch (cmd) { switch (cmd) {
case F_GETLK:
case F_SETLK:
case F_SETLKW:
ret = get_flock(&fl64, (struct flock32 *)arg);
arg = (unsigned long) &fl64;
set_fs(KERNEL_DS);
break;
case F_GETLK64: case F_GETLK64:
cmd = F_GETLK; cmd = F_GETLK;
goto cnv64; goto cnv;
case F_SETLK64: case F_SETLK64:
cmd = F_SETLK; cmd = F_SETLK;
goto cnv64; goto cnv;
case F_SETLKW64: case F_SETLKW64:
cmd = F_SETLKW; cmd = F_SETLKW;
cnv64: cnv:
ret = get_flock64((struct ia32_flock64 *)arg, &fl64); ret = get_flock64((struct ia32_flock64 *)arg, &fl64);
arg = (unsigned long)&fl64; arg = (unsigned long)&fl64;
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
break; break;
case F_GETLK:
case F_SETLK:
case F_SETLKW:
return sys32_fcntl(fd,cmd,arg);
} }
if (!ret) if (!ret)
ret = sys_fcntl(fd, cmd, arg); ret = sys_fcntl(fd, cmd, arg);
set_fs(oldfs); set_fs(oldfs);
if (origcmd == F_GETLK && !ret) if (oldcmd == F_GETLK64 && !ret)
ret = put_flock(&fl64, (struct flock32 *)origarg); ret = put_flock64((struct ia32_flock64 *)oldarg, &fl64);
else if (cmd == F_GETLK && !ret)
ret = put_flock64((struct ia32_flock64 *)origarg, &fl64);
return ret; return ret;
} }
...@@ -1804,19 +1845,6 @@ sys32_sysctl(struct sysctl_ia32 *args32) ...@@ -1804,19 +1845,6 @@ sys32_sysctl(struct sysctl_ia32 *args32)
#endif #endif
} }
extern asmlinkage long sys_newuname(struct new_utsname * name);
asmlinkage long
sys32_newuname(struct new_utsname * name)
{
int ret = sys_newuname(name);
if (current->personality == PER_LINUX32 && !ret) {
ret = copy_to_user(name->machine, "i686\0\0", 6);
}
return ret;
}
extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf, extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
size_t count, loff_t pos); size_t count, loff_t pos);
...@@ -1825,7 +1853,8 @@ extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf, ...@@ -1825,7 +1853,8 @@ extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
typedef __kernel_ssize_t32 ssize_t32; typedef __kernel_ssize_t32 ssize_t32;
/* warning. next two assume LE */
/* warning: next two assume little endian */
asmlinkage ssize_t32 asmlinkage ssize_t32
sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count, sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
u32 poslo, u32 poshi) u32 poslo, u32 poshi)
...@@ -1849,7 +1878,8 @@ asmlinkage long ...@@ -1849,7 +1878,8 @@ asmlinkage long
sys32_personality(unsigned long personality) sys32_personality(unsigned long personality)
{ {
int ret; int ret;
if (current->personality == PER_LINUX32 && personality == PER_LINUX) if (personality(current->personality) == PER_LINUX32 &&
personality == PER_LINUX)
personality = PER_LINUX32; personality = PER_LINUX32;
ret = sys_personality(personality); ret = sys_personality(personality);
if (ret == PER_LINUX32) if (ret == PER_LINUX32)
...@@ -1956,42 +1986,39 @@ sys32_adjtimex(struct timex32 *utp) ...@@ -1956,42 +1986,39 @@ sys32_adjtimex(struct timex32 *utp)
return ret; return ret;
} }
asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
/* common code for old and new mmaps */
static inline long do_mmap2(
unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff) unsigned long fd, unsigned long pgoff)
{ {
int error = -EBADF; struct mm_struct *mm = current->mm;
unsigned long error;
struct file * file = NULL; struct file * file = NULL;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
if (!(flags & MAP_ANONYMOUS)) { if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd); file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
} }
down_write(&current->mm->mmap_sem); /* later add PROT_EXEC for PROT_READ here */
error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
up_write(&current->mm->mmap_sem); 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) {
do_munmap(mm, error, len);
error = -ENOMEM;
}
if (file) if (file)
fput(file); fput(file);
out:
return error; return error;
} }
asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, asmlinkage long sys32_olduname(struct oldold_utsname * name)
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
{
return do_mmap2(addr, len, prot, flags, fd, pgoff);
}
asmlinkage int sys32_olduname(struct oldold_utsname * name)
{ {
int error; int error;
...@@ -2581,6 +2608,19 @@ long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) ...@@ -2581,6 +2608,19 @@ long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
return ret; return ret;
} }
int sys32_vm86_warning(void)
{
static long warn_time = -(60*HZ);
if (time_before(warn_time + 60*HZ,jiffies)) {
printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
current->comm);
warn_time = jiffies;
}
return -ENOSYS ;
}
struct exec_domain ia32_exec_domain = { struct exec_domain ia32_exec_domain = {
.name = "linux/x86", .name = "linux/x86",
.pers_low = PER_LINUX32, .pers_low = PER_LINUX32,
......
...@@ -9,7 +9,7 @@ export-objs := mtrr.o x8664_ksyms.o pci-gart.o ...@@ -9,7 +9,7 @@ export-objs := mtrr.o x8664_ksyms.o pci-gart.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.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 \ 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 \ pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \
setup64.o bluesmoke.o bootflag.o e820.o reboot.o setup64.o bluesmoke.o bootflag.o e820.o reboot.o profile.o
obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_MTRR) += mtrr.o
obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_MSR) += msr.o
......
...@@ -897,17 +897,9 @@ int setup_profiling_timer(unsigned int multiplier) ...@@ -897,17 +897,9 @@ int setup_profiling_timer(unsigned int multiplier)
inline void smp_local_timer_interrupt(struct pt_regs *regs) inline void smp_local_timer_interrupt(struct pt_regs *regs)
{ {
int user = user_mode(regs);
int cpu = smp_processor_id(); int cpu = smp_processor_id();
/* x86_do_profile(regs);
* The profiling function is SMP safe. (nothing can mess
* around with "current", and the profiling counters are
* updated with atomic operations). This is especially
* useful with a profiling multiplier != 1
*/
if (!user)
x86_do_profile(regs->rip);
if (--prof_counter[cpu] <= 0) { if (--prof_counter[cpu] <= 0) {
/* /*
...@@ -925,7 +917,7 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs) ...@@ -925,7 +917,7 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs)
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
update_process_times(user); update_process_times(user_mode(regs));
#endif #endif
} }
...@@ -951,8 +943,6 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs) ...@@ -951,8 +943,6 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs)
*/ */
void smp_apic_timer_interrupt(struct pt_regs *regs) void smp_apic_timer_interrupt(struct pt_regs *regs)
{ {
int cpu = smp_processor_id();
/* /*
* the NMI deadlock-detector uses this. * the NMI deadlock-detector uses this.
*/ */
...@@ -1084,11 +1074,13 @@ int __init APIC_init_uniprocessor (void) ...@@ -1084,11 +1074,13 @@ int __init APIC_init_uniprocessor (void)
static __init int setup_disableapic(char *str) static __init int setup_disableapic(char *str)
{ {
disable_apic = 1; disable_apic = 1;
return 0;
} }
static __init int setup_noapictimer(char *str) static __init int setup_noapictimer(char *str)
{ {
disable_apic_timer = 1; disable_apic_timer = 1;
return 0;
} }
__setup("disableapic", setup_disableapic); __setup("disableapic", setup_disableapic);
......
...@@ -785,7 +785,7 @@ void __init mp_register_ioapic ( ...@@ -785,7 +785,7 @@ void __init mp_register_ioapic (
mp_ioapic_routing[idx].irq_end = irq_base + mp_ioapic_routing[idx].irq_end = irq_base +
io_apic_get_redir_entries(idx); io_apic_get_redir_entries(idx);
printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, " printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
"IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, "IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
mp_ioapic_routing[idx].irq_start, mp_ioapic_routing[idx].irq_start,
......
...@@ -646,7 +646,7 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment) ...@@ -646,7 +646,7 @@ int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment)
} }
if (base & (size_or_mask>>PAGE_SHIFT)) { if (base & (size_or_mask>>PAGE_SHIFT)) {
printk (KERN_WARNING "mtrr: base(%lx) exceeds the MTRR width(%lx)\n", printk (KERN_WARNING "mtrr: base(%Lx) exceeds the MTRR width(%Lx)\n",
base, (size_or_mask>>PAGE_SHIFT)); base, (size_or_mask>>PAGE_SHIFT));
return -EINVAL; return -EINVAL;
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/nmi.h>
unsigned int nmi_watchdog = NMI_LOCAL_APIC; unsigned int nmi_watchdog = NMI_LOCAL_APIC;
static unsigned int nmi_hz = HZ; static unsigned int nmi_hz = HZ;
...@@ -137,6 +138,18 @@ static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ...@@ -137,6 +138,18 @@ static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
return 0; return 0;
} }
struct pm_dev * set_nmi_pm_callback(pm_callback callback)
{
apic_pm_unregister(nmi_pmdev);
return apic_pm_register(PM_SYS_DEV, 0, callback);
}
void unset_nmi_pm_callback(struct pm_dev * dev)
{
apic_pm_unregister(dev);
nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
}
static void nmi_pm_init(void) static void nmi_pm_init(void)
{ {
if (!nmi_pmdev) if (!nmi_pmdev)
...@@ -178,7 +191,7 @@ static void __pminit setup_k7_watchdog(void) ...@@ -178,7 +191,7 @@ static void __pminit setup_k7_watchdog(void)
| K7_NMI_EVENT; | K7_NMI_EVENT;
wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
printk(KERN_INFO "watchdog: setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); printk(KERN_INFO "watchdog: setting K7_PERFCTR0 to %08x\n", -(cpu_khz/nmi_hz*1000));
wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
apic_write(APIC_LVTPC, APIC_DM_NMI); apic_write(APIC_LVTPC, APIC_DM_NMI);
evntsel |= K7_EVNTSEL_ENABLE; evntsel |= K7_EVNTSEL_ENABLE;
...@@ -275,3 +288,30 @@ void nmi_watchdog_tick (struct pt_regs * regs) ...@@ -275,3 +288,30 @@ void nmi_watchdog_tick (struct pt_regs * regs)
if (nmi_perfctr_msr) if (nmi_perfctr_msr)
wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
} }
static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
{
return 0;
}
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();
add_pda(__nmi_count,1);
if (!nmi_callback(regs, cpu))
default_do_nmi(regs);
}
void set_nmi_callback(nmi_callback_t callback)
{
nmi_callback = callback;
}
void unset_nmi_callback(void)
{
nmi_callback = dummy_nmi_callback;
}
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/user.h> #include <linux/user.h>
#include <linux/module.h>
#include <linux/a.out.h> #include <linux/a.out.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/config.h> #include <linux/config.h>
......
/*
* linux/arch/i386/kernel/profile.c
*
* (C) 2002 John Levon <levon@movementarian.org>
*
*/
#include <linux/profile.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <linux/irq.h>
#include <asm/hw_irq.h>
static struct notifier_block * profile_listeners;
static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
int register_profile_notifier(struct notifier_block * nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_register(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
int unregister_profile_notifier(struct notifier_block * nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_unregister(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
void x86_profile_hook(struct pt_regs * regs)
{
/* we would not even need this lock if
* we had a global cli() on register/unregister
*/
read_lock(&profile_lock);
notifier_call_chain(&profile_listeners, 0, regs);
read_unlock(&profile_lock);
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/hw_irq.h>
/* /*
......
...@@ -234,7 +234,6 @@ static void __init contig_initmem_init(void) ...@@ -234,7 +234,6 @@ static void __init contig_initmem_init(void)
void __init setup_arch(char **cmdline_p) void __init setup_arch(char **cmdline_p)
{ {
unsigned long bootmap_size, low_mem_size;
int i; int i;
ROOT_DEV = ORIG_ROOT_DEV; ROOT_DEV = ORIG_ROOT_DEV;
...@@ -284,14 +283,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -284,14 +283,8 @@ void __init setup_arch(char **cmdline_p)
contig_initmem_init(); contig_initmem_init();
/* /* reserve kernel */
* Reserve the bootmem bitmap itself as well. We do this in two reserve_bootmem(HIGH_MEMORY, PFN_PHYS(start_pfn) - HIGH_MEMORY);
* steps (first step was init_bootmem()) because this catches
* the (very unlikely) case of us accidentally initializing the
* bootmem allocator with an invalid RAM area.
*/
reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
/* /*
* reserve physical page 0 - it's a special BIOS page on many boxes, * reserve physical page 0 - it's a special BIOS page on many boxes,
......
...@@ -559,11 +559,10 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) ...@@ -559,11 +559,10 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
printk("Do you have a strange power saving mode enabled?\n"); printk("Do you have a strange power saving mode enabled?\n");
} }
asmlinkage void do_nmi(struct pt_regs * regs) asmlinkage void default_do_nmi(struct pt_regs * regs)
{ {
unsigned char reason = inb(0x61); unsigned char reason = inb(0x61);
add_pda(__nmi_count,1);
if (!(reason & 0xc0)) { if (!(reason & 0xc0)) {
#if CONFIG_X86_LOCAL_APIC #if CONFIG_X86_LOCAL_APIC
/* /*
......
# #
# Makefile for the linux i386-specific parts of the memory manager. # Makefile for the linux i386-specific parts of the memory manager.
# #
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o export-objs := pageattr.o
obj-y := init.o fault.o ioremap.o extable.o modutil.o
obj-y := init.o fault.o ioremap.o extable.o modutil.o pageattr.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -32,18 +32,14 @@ ...@@ -32,18 +32,14 @@
extern void die(const char *,struct pt_regs *,long); extern void die(const char *,struct pt_regs *,long);
extern spinlock_t console_lock, timerlist_lock; extern spinlock_t console_lock;
void bust_spinlocks(int yes) void bust_spinlocks(int yes)
{ {
spin_lock_init(&timerlist_lock); int loglevel_save = console_loglevel;
if (yes) { if (yes) {
oops_in_progress = 1; oops_in_progress = 1;
#ifdef CONFIG_SMP
global_irq_lock = 0; /* Many serial drivers do __global_cli() */
#endif
} else { } else {
int loglevel_save = console_loglevel;
#ifdef CONFIG_VT #ifdef CONFIG_VT
unblank_screen(); unblank_screen();
#endif #endif
...@@ -108,6 +104,18 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -108,6 +104,18 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
int write; int write;
siginfo_t info; siginfo_t info;
#ifdef CONFIG_CHECKING
{
unsigned long gs;
struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
printk("page_fault: wrong gs %lx expected %p\n", gs, pda);
}
}
#endif
/* get the address */ /* get the address */
__asm__("movq %%cr2,%0":"=r" (address)); __asm__("movq %%cr2,%0":"=r" (address));
...@@ -129,7 +137,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -129,7 +137,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
* If we're in an interrupt or have no user * If we're in an interrupt or have no user
* context, we must not take the fault.. * context, we must not take the fault..
*/ */
if (in_interrupt() || !mm) if (in_atomic() || !mm)
goto no_context; goto no_context;
again: again:
...@@ -223,7 +231,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -223,7 +231,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* Are we prepared to handle this kernel fault? */ /* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->rip)) != 0) { if ((fixup = search_exception_table(regs->rip)) != 0) {
regs->rip = fixup; regs->rip = fixup;
if (exception_trace) if (0 && exception_trace)
printk(KERN_ERR printk(KERN_ERR
"%s: fixed kernel exception at %lx address %lx err:%ld\n", "%s: fixed kernel exception at %lx address %lx err:%ld\n",
current->comm, regs->rip, address, error_code); current->comm, regs->rip, address, error_code);
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
unsigned long start_pfn, end_pfn;
mmu_gather_t mmu_gathers[NR_CPUS]; mmu_gather_t mmu_gathers[NR_CPUS];
/* /*
...@@ -49,19 +51,24 @@ void show_mem(void) ...@@ -49,19 +51,24 @@ void show_mem(void)
{ {
int i, total = 0, reserved = 0; int i, total = 0, reserved = 0;
int shared = 0, cached = 0; int shared = 0, cached = 0;
pg_data_t *pgdat;
struct page *page;
printk("Mem-info:\n"); printk("Mem-info:\n");
show_free_areas(); show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
while (i-- > 0) { for_each_pgdat(pgdat) {
for (i = 0; i < pgdat->node_size; ++i) {
page = pgdat->node_mem_map + i;
total++; total++;
if (PageReserved(mem_map+i)) if (PageReserved(page))
reserved++; reserved++;
else if (PageSwapCache(mem_map+i)) else if (PageSwapCache(page))
cached++; cached++;
else if (page_count(mem_map+i)) else if (page_count(page))
shared += page_count(mem_map+i) - 1; shared += page_count(page) - 1;
}
} }
printk("%d pages of RAM\n", total); printk("%d pages of RAM\n", total);
printk("%d reserved pages\n",reserved); printk("%d reserved pages\n",reserved);
...@@ -264,16 +271,15 @@ void __init paging_init(void) ...@@ -264,16 +271,15 @@ void __init paging_init(void)
{ {
{ {
unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
unsigned int max_dma, low; unsigned int max_dma;
max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
low = max_low_pfn;
if (low < max_dma) if (end_pfn < max_dma)
zones_size[ZONE_DMA] = low; zones_size[ZONE_DMA] = end_pfn;
else { else {
zones_size[ZONE_DMA] = max_dma; zones_size[ZONE_DMA] = max_dma;
zones_size[ZONE_NORMAL] = low - max_dma; zones_size[ZONE_NORMAL] = end_pfn - max_dma;
} }
free_area_init(zones_size); free_area_init(zones_size);
} }
...@@ -308,11 +314,15 @@ void __init mem_init(void) ...@@ -308,11 +314,15 @@ void __init mem_init(void)
int codesize, reservedpages, datasize, initsize; int codesize, reservedpages, datasize, initsize;
int tmp; int tmp;
printk("mem_init\n");
if (!mem_map) if (!mem_map)
BUG(); BUG();
max_mapnr = num_physpages = max_low_pfn; max_low_pfn = end_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); max_pfn = end_pfn;
max_mapnr = num_physpages = end_pfn;
high_memory = (void *) __va(end_pfn * PAGE_SIZE);
/* clear the zero-page */ /* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE); memset(empty_zero_page, 0, PAGE_SIZE);
...@@ -323,7 +333,7 @@ void __init mem_init(void) ...@@ -323,7 +333,7 @@ void __init mem_init(void)
after_bootmem = 1; after_bootmem = 1;
reservedpages = 0; reservedpages = 0;
for (tmp = 0; tmp < max_low_pfn; tmp++) for (tmp = 0; tmp < end_pfn; tmp++)
/* /*
* Only count reserved RAM pages * Only count reserved RAM pages
*/ */
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
...@@ -157,14 +158,72 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag ...@@ -157,14 +158,72 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
return NULL; return NULL;
addr = area->addr; addr = area->addr;
if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
vfree(addr); vunmap(addr);
return NULL; return NULL;
} }
return (void *) (offset + (char *)addr); return (void *) (offset + (char *)addr);
} }
/**
* ioremap_nocache - map bus memory into CPU space
* @offset: bus address of the memory
* @size: size of the resource to map
*
* ioremap_nocache performs a platform specific sequence of operations to
* make bus memory CPU accessible via the readb/readw/readl/writeb/
* writew/writel functions and the other mmio helpers. The returned
* address is not guaranteed to be usable directly as a virtual
* address.
*
* This version of ioremap ensures that the memory is marked uncachable
* on the CPU as well as honouring existing caching rules from things like
* the PCI bus. Note that there are other caches and buffers on many
* busses. In particular driver authors should read up on PCI writes
*
* It's useful if some control registers are in such an area and
* write combining or read caching is not desirable:
*
* Must be freed with iounmap.
*/
void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
{
void *p = __ioremap(phys_addr, size, _PAGE_PCD);
if (!p)
return p;
if (phys_addr + size < virt_to_phys(high_memory)) {
struct page *ppage = virt_to_page(__va(phys_addr));
unsigned long npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
BUG_ON(phys_addr+size > (unsigned long)high_memory);
BUG_ON(phys_addr + size < phys_addr);
if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) {
iounmap(p);
p = NULL;
}
}
return p;
}
void iounmap(void *addr) void iounmap(void *addr)
{ {
if (addr > high_memory) struct vm_struct *p;
vfree((void *) (PAGE_MASK & (unsigned long) addr)); if (addr <= high_memory)
return;
p = remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
if (!p) {
printk("__iounmap: bad address %p\n", addr);
return;
}
unmap_vm_area(p);
if (p->flags && p->phys_addr < virt_to_phys(high_memory)) {
change_page_attr(virt_to_page(__va(p->phys_addr)),
p->size >> PAGE_SHIFT,
PAGE_KERNEL);
}
kfree(p);
} }
...@@ -13,12 +13,15 @@ ...@@ -13,12 +13,15 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
static struct vm_struct * modvmlist = NULL; static struct vm_struct * modvmlist = NULL;
void module_unmap (void * addr) void module_unmap (void * addr)
{ {
struct vm_struct **p, *tmp; struct vm_struct **p, *tmp;
int i;
if (!addr) if (!addr)
return; return;
...@@ -29,21 +32,33 @@ void module_unmap (void * addr) ...@@ -29,21 +32,33 @@ void module_unmap (void * addr)
for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) { for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) { if (tmp->addr == addr) {
*p = tmp->next; *p = tmp->next;
vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); goto found;
kfree(tmp);
return;
} }
} }
printk("Trying to unmap nonexistent module vm area (%p)\n", addr); printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
return;
found:
unmap_vm_area(tmp);
for (i = 0; i < tmp->nr_pages; i++) {
if (unlikely(!tmp->pages[i]))
BUG();
__free_page(tmp->pages[i]);
}
kfree(tmp->pages);
kfree(tmp);
} }
void * module_map (unsigned long size) void * module_map (unsigned long size)
{ {
void * addr;
struct vm_struct **p, *tmp, *area; struct vm_struct **p, *tmp, *area;
struct page **pages;
void * addr;
unsigned int nr_pages, array_size, i;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
if (!size || size > MODULES_LEN) return NULL; if (!size || size > MODULES_LEN)
return NULL;
addr = (void *) MODULES_VADDR; addr = (void *) MODULES_VADDR;
for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) { for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
...@@ -51,18 +66,53 @@ void * module_map (unsigned long size) ...@@ -51,18 +66,53 @@ void * module_map (unsigned long size)
break; break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr); addr = (void *) (tmp->size + (unsigned long) tmp->addr);
} }
if ((unsigned long) addr + size >= MODULES_END) return NULL; if ((unsigned long) addr + size >= MODULES_END)
return NULL;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL); area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area) return NULL; if (!area)
return NULL;
area->size = size + PAGE_SIZE; area->size = size + PAGE_SIZE;
area->addr = addr; area->addr = addr;
area->next = *p; area->next = *p;
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
*p = area; *p = area;
if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) { nr_pages = size >> PAGE_SHIFT;
module_unmap(addr); array_size = (nr_pages * sizeof(struct page *));
return NULL;
area->nr_pages = nr_pages;
area->pages = pages = kmalloc(array_size, GFP_KERNEL);
if (!area->pages)
goto fail;
memset(area->pages, 0, array_size);
for (i = 0; i < area->nr_pages; i++) {
area->pages[i] = alloc_page(GFP_KERNEL);
if (unlikely(!area->pages[i]))
goto fail;
}
if (map_vm_area(area, PAGE_KERNEL, &pages)) {
unmap_vm_area(area);
goto fail;
} }
return addr;
return area->addr;
fail:
if (area->pages) {
for (i = 0; i < area->nr_pages; i++) {
if (area->pages[i])
__free_page(area->pages[i]);
}
kfree(area->pages);
}
kfree(area);
return NULL;
} }
/*
* Copyright 2002 Andi Kleen, SuSE Labs.
* Thanks to Ben LaHaise for precious feedback.
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
#include <asm/io.h>
static inline pte_t *lookup_address(unsigned long address)
{
pgd_t *pgd = pgd_offset_k(address);
pmd_t *pmd;
pte_t *pte;
if (!pgd || !pgd_present(*pgd))
return NULL;
pmd = pmd_offset(pgd, address);
if (!pmd_present(*pmd))
return NULL;
if (pmd_large(*pmd))
return (pte_t *)pmd;
pte = pte_offset_kernel(pmd, address);
if (pte && !pte_present(*pte))
pte = NULL;
return pte;
}
static struct page *split_large_page(unsigned long address, pgprot_t prot)
{
int i;
unsigned long addr;
struct page *base = alloc_pages(GFP_KERNEL, 0);
pte_t *pbase;
if (!base)
return NULL;
address = __pa(address);
addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
pbase[i] = pfn_pte(addr >> PAGE_SHIFT,
addr == address ? prot : PAGE_KERNEL);
}
return base;
}
static void flush_kernel_map(void *address)
{
if (address && cpu_has_clflush) {
/* is this worth it? */
int i;
for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
asm volatile("clflush %0" :: "m" (address + i));
} else
asm volatile("wbinvd":::"memory");
__flush_tlb_one(address);
}
/*
* No more special protections in this 2/4MB area - revert to a
* large page again.
*/
static inline void revert_page(struct page *kpte_page, unsigned long address)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t large_pte;
pgd = pgd_offset_k(address);
if (!pgd) BUG();
pmd = pmd_offset(pgd, address);
if (!pmd) BUG();
if ((pmd_val(*pmd) & _PAGE_GLOBAL) == 0) BUG();
large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, PAGE_KERNEL_LARGE);
set_pte((pte_t *)pmd, large_pte);
}
static int
__change_page_attr(unsigned long address, struct page *page, pgprot_t prot,
struct page **oldpage)
{
pte_t *kpte;
struct page *kpte_page;
unsigned kpte_flags;
kpte = lookup_address(address);
if (!kpte) return 0;
kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
kpte_flags = pte_val(*kpte);
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) {
if ((kpte_flags & _PAGE_PSE) == 0) {
pte_t old = *kpte;
pte_t standard = mk_pte(page, PAGE_KERNEL);
set_pte(kpte, mk_pte(page, prot));
if (pte_same(old,standard))
atomic_inc(&kpte_page->count);
} else {
struct page *split = split_large_page(address, prot);
if (!split)
return -ENOMEM;
set_pte(kpte,mk_pte(split, PAGE_KERNEL));
}
} else if ((kpte_flags & _PAGE_PSE) == 0) {
set_pte(kpte, mk_pte(page, PAGE_KERNEL));
atomic_dec(&kpte_page->count);
}
if (atomic_read(&kpte_page->count) == 1) {
*oldpage = kpte_page;
revert_page(kpte_page, address);
}
return 0;
}
static inline void flush_map(unsigned long address)
{
#ifdef CONFIG_SMP
smp_call_function(flush_kernel_map, (void *)address, 1, 1);
#endif
flush_kernel_map((void *)address);
}
struct deferred_page {
struct deferred_page *next;
struct page *fpage;
unsigned long address;
};
static struct deferred_page *df_list; /* protected by init_mm.mmap_sem */
static inline void save_page(unsigned long address, struct page *fpage)
{
struct deferred_page *df;
df = kmalloc(sizeof(struct deferred_page), GFP_KERNEL);
if (!df) {
flush_map(address);
__free_page(fpage);
} else {
df->next = df_list;
df->fpage = fpage;
df->address = address;
df_list = df;
}
}
/*
* Change the page attributes of an page in the linear mapping.
*
* This should be used when a page is mapped with a different caching policy
* than write-back somewhere - some CPUs do not like it when mappings with
* different caching policies exist. This changes the page attributes of the
* in kernel linear mapping too.
*
* The caller needs to ensure that there are no conflicting mappings elsewhere.
* This function only deals with the kernel linear map.
*
* Caller must call global_flush_tlb() after this.
*/
int change_page_attr(struct page *page, int numpages, pgprot_t prot)
{
int err = 0;
struct page *fpage, *fpage2;
int i;
down_write(&init_mm.mmap_sem);
for (i = 0; i < numpages; i++, page++) {
unsigned long address = (unsigned long)page_address(page);
fpage = NULL;
err = __change_page_attr(address, page, prot, &fpage);
/* Handle kernel mapping too which aliases part of the lowmem */
if (!err && page_to_phys(page) < KERNEL_TEXT_SIZE) {
unsigned long addr2 = __START_KERNEL_map + page_to_phys(page);
fpage2 = NULL;
err = __change_page_attr(addr2, page, prot, &fpage2);
if (fpage2)
save_page(addr2, fpage2);
}
if (fpage)
save_page(address, fpage);
}
up_write(&init_mm.mmap_sem);
return err;
}
void global_flush_tlb(void)
{
struct deferred_page *df, *next_df;
down_read(&init_mm.mmap_sem);
df = xchg(&df_list, NULL);
up_read(&init_mm.mmap_sem);
flush_map((df && !df->next) ? df->address : 0);
for (; df; df = next_df) {
next_df = df->next;
if (df->fpage)
__free_page(df->fpage);
kfree(df);
}
}
EXPORT_SYMBOL(change_page_attr);
EXPORT_SYMBOL(global_flush_tlb);
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/profile.h>
#include <linux/smp.h>
struct hw_interrupt_type;
#endif #endif
/* /*
...@@ -126,20 +130,23 @@ __asm__( \ ...@@ -126,20 +130,23 @@ __asm__( \
"push $" #nr "-256 ; " \ "push $" #nr "-256 ; " \
"jmp common_interrupt"); "jmp common_interrupt");
extern unsigned long prof_cpu_mask; static inline void x86_do_profile (struct pt_regs *regs)
extern unsigned int * prof_buffer;
extern unsigned long prof_len;
extern unsigned long prof_shift;
/*
* x86 profiling function, SMP safe. We might want to do this in
* assembly totally?
*/
static inline void x86_do_profile (unsigned long rip)
{ {
unsigned long rip;
extern unsigned long prof_cpu_mask;
extern char _stext;
#ifdef CONFIG_PROFILING
extern void x86_profile_hook(struct pt_regs *);
x86_profile_hook(regs);
#endif
if (user_mode(regs))
return;
if (!prof_buffer) if (!prof_buffer)
return; return;
rip = regs->rip;
/* /*
* Only measure the CPUs specified by /proc/irq/prof_cpu_mask. * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
* (default is all CPUs.) * (default is all CPUs.)
...@@ -159,6 +166,11 @@ static inline void x86_do_profile (unsigned long rip) ...@@ -159,6 +166,11 @@ static inline void x86_do_profile (unsigned long rip)
atomic_inc((atomic_t *)&prof_buffer[rip]); atomic_inc((atomic_t *)&prof_buffer[rip]);
} }
struct notifier_block;
int register_profile_notifier(struct notifier_block * nb);
int unregister_profile_notifier(struct notifier_block * nb);
#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */ #ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
if (IO_APIC_IRQ(i)) if (IO_APIC_IRQ(i))
......
...@@ -235,11 +235,6 @@ struct iovec32 { ...@@ -235,11 +235,6 @@ struct iovec32 {
}; };
#ifdef __KERNEL__
struct iovec *get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type);
#endif
#endif /* !CONFIG_IA32_SUPPORT */ #endif /* !CONFIG_IA32_SUPPORT */
#endif #endif
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
*/ */
/* /*
* This file contains the i386 architecture specific IDE code. * This file contains the x86_64 architecture specific IDE code.
*/ */
#ifndef __ASMx86_64_IDE_H #ifndef __ASMx86_64_IDE_H
......
...@@ -148,9 +148,18 @@ extern int io_apic_get_redir_entries (int ioapic); ...@@ -148,9 +148,18 @@ extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
#endif #endif
#ifdef CONFIG_ACPI_BOOT
extern int io_apic_get_unique_id (int ioapic, int apic_id);
extern int io_apic_get_version (int ioapic);
extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
#endif
#else /* !CONFIG_X86_IO_APIC */ #else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0 #define io_apic_assign_pci_irqs 0
#endif #endif
void enable_NMI_through_LVT0 (void * dummy);
#endif #endif
#include <linux/ioctl32.h>
#ifndef __x86_64_IPC_H__ #ifndef __x8664_IPC_H__
#define __x86_64_IPC_H__ #define __x8664_IPC_H__
/* dummy */ /* dummy */
......
#ifndef __i386_IPCBUF_H__ #ifndef __x86_64_IPCBUF_H__
#define __i386_IPCBUF_H__ #define __x86_64_IPCBUF_H__
/* /*
* The ipc64_perm structure for i386 architecture. * The ipc64_perm structure for x86_64 architecture.
* Note extra padding because this structure is passed back and forth * Note extra padding because this structure is passed back and forth
* between kernel and user space. * between kernel and user space.
* *
...@@ -26,4 +26,4 @@ struct ipc64_perm ...@@ -26,4 +26,4 @@ struct ipc64_perm
unsigned long __unused2; unsigned long __unused2;
}; };
#endif /* __i386_IPCBUF_H__ */ #endif /* __x86_64_IPCBUF_H__ */
/* $Id: namei.h,v 1.2 2001/07/04 09:08:13 ak Exp $
* linux/include/asm-i386/namei.h
*
* Included from linux/fs/namei.c
*/
#ifndef __X8664_NAMEI_H #ifndef __X8664_NAMEI_H
#define __X8664_NAMEI_H #define __X8664_NAMEI_H
......
/*
* linux/include/asm-i386/nmi.h
*/
#ifndef ASM_NMI_H
#define ASM_NMI_H
#include <linux/pm.h>
struct pt_regs;
typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
/**
* set_nmi_callback
*
* Set a handler for an NMI. Only one handler may be
* set. Return 1 if the NMI was handled.
*/
void set_nmi_callback(nmi_callback_t callback);
/**
* unset_nmi_callback
*
* Remove the handler previously set.
*/
void unset_nmi_callback(void);
#ifdef CONFIG_PM
/** Replace the PM callback routine for NMI. */
struct pm_dev * set_nmi_pm_callback(pm_callback callback);
/** Unset the PM callback routine back to the default. */
void unset_nmi_pm_callback(struct pm_dev * dev);
#else
static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
{
return 0;
}
static inline void unset_nmi_pm_callback(struct pm_dev * dev)
{
}
#endif /* CONFIG_PM */
#endif /* ASM_NMI_H */
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define _ASMx86_64_PARAM_H #define _ASMx86_64_PARAM_H
#ifdef __KERNEL__ #ifdef __KERNEL__
# define HZ 100 /* Internal kernel timer frequency */ # define HZ 1000 /* Internal kernel timer frequency */
# define USER_HZ 100 /* .. some user interfaces are in "ticks */ # define USER_HZ 100 /* .. some user interfaces are in "ticks */
#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif #endif
......
...@@ -42,6 +42,7 @@ extern void exception_table_check(void); ...@@ -42,6 +42,7 @@ extern void exception_table_check(void);
extern void acpi_boot_init(char *); extern void acpi_boot_init(char *);
int iommu_setup(char *opt);
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define round_down(x,y) ((x) & ~((y)-1)) #define round_down(x,y) ((x) & ~((y)-1))
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#define __local_bh_enable() \ #define __local_bh_enable() \
do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0) do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
void do_softirq(void);
#define local_bh_enable() \ #define local_bh_enable() \
do { \ do { \
__local_bh_enable(); \ __local_bh_enable(); \
......
...@@ -482,8 +482,10 @@ __SYSCALL(__NR_io_submit, sys_io_submit) ...@@ -482,8 +482,10 @@ __SYSCALL(__NR_io_submit, sys_io_submit)
__SYSCALL(__NR_io_cancel, sys_io_cancel) __SYSCALL(__NR_io_cancel, sys_io_cancel)
#define __NR_get_thread_area 211 #define __NR_get_thread_area 211
__SYSCALL(__NR_get_thread_area, sys_get_thread_area) __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_get_thread_area #define __NR_syscall_max __NR_lookup_dcookie
#ifndef __NO_STUBS #ifndef __NO_STUBS
/* user-visible error numbers are in the range -1 - -4095 */ /* user-visible error numbers are in the range -1 - -4095 */
...@@ -503,7 +505,6 @@ do { \ ...@@ -503,7 +505,6 @@ do { \
#define __syscall "syscall" #define __syscall "syscall"
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \ #define _syscall0(type,name) \
type name(void) \ type name(void) \
{ \ { \
......
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