Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
* git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86: (78 commits) x86: fix RTC lockdep warning: potential hardirq recursion x86: cpa, micro-optimization x86: cpa, clean up code flow x86: cpa, eliminate CPA_ enum x86: cpa, cleanups x86: implement gbpages support in change_page_attr() x86: support gbpages in pagetable dump x86: add gbpages support to lookup_address x86: add pgtable accessor functions for gbpages x86: add PUD_PAGE_SIZE x86: add feature macros for the gbpages cpuid bit x86: switch direct mapping setup over to set_pte x86: fix page-present check in cpa_flush_range x86: remove cpa warning x86: remove now unused clear_kernel_mapping x86: switch pci-gart over to using set_memory_np() instead of clear_kernel_mapping() x86: cpa selftest, skip non present entries x86: CPA fix pagetable split x86: rename LARGE_PAGE_SIZE to PMD_PAGE_SIZE x86: cpa, fix lookup_address ...
This commit is contained in:
commit
d2fc0bacd5
68 changed files with 823 additions and 816 deletions
16
Documentation/x86_64/00-INDEX
Normal file
16
Documentation/x86_64/00-INDEX
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
00-INDEX
|
||||||
|
- This file
|
||||||
|
boot-options.txt
|
||||||
|
- AMD64-specific boot options.
|
||||||
|
cpu-hotplug-spec
|
||||||
|
- Firmware support for CPU hotplug under Linux/x86-64
|
||||||
|
fake-numa-for-cpusets
|
||||||
|
- Using numa=fake and CPUSets for Resource Management
|
||||||
|
kernel-stacks
|
||||||
|
- Context-specific per-processor interrupt stacks.
|
||||||
|
machinecheck
|
||||||
|
- Configurable sysfs parameters for the x86-64 machine check code.
|
||||||
|
mm.txt
|
||||||
|
- Memory layout of x86-64 (4 level page tables, 46 bits physical).
|
||||||
|
uefi.txt
|
||||||
|
- Booting Linux via Unified Extensible Firmware Interface.
|
|
@ -306,6 +306,7 @@ config X86_RDC321X
|
||||||
select M486
|
select M486
|
||||||
select X86_REBOOTFIXUPS
|
select X86_REBOOTFIXUPS
|
||||||
select GENERIC_GPIO
|
select GENERIC_GPIO
|
||||||
|
select LEDS_CLASS
|
||||||
select LEDS_GPIO
|
select LEDS_GPIO
|
||||||
help
|
help
|
||||||
This option is needed for RDC R-321x system-on-chip, also known
|
This option is needed for RDC R-321x system-on-chip, also known
|
||||||
|
|
|
@ -92,7 +92,6 @@ KBUILD_AFLAGS += $(cfi) $(cfi-sigframe)
|
||||||
KBUILD_CFLAGS += $(cfi) $(cfi-sigframe)
|
KBUILD_CFLAGS += $(cfi) $(cfi-sigframe)
|
||||||
|
|
||||||
LDFLAGS := -m elf_$(UTS_MACHINE)
|
LDFLAGS := -m elf_$(UTS_MACHINE)
|
||||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
|
||||||
|
|
||||||
# Speed up the build
|
# Speed up the build
|
||||||
KBUILD_CFLAGS += -pipe
|
KBUILD_CFLAGS += -pipe
|
||||||
|
|
|
@ -26,7 +26,7 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
|
||||||
#RAMDISK := -DRAMDISK=512
|
#RAMDISK := -DRAMDISK=512
|
||||||
|
|
||||||
targets := vmlinux.bin setup.bin setup.elf zImage bzImage
|
targets := vmlinux.bin setup.bin setup.elf zImage bzImage
|
||||||
subdir- := compressed
|
subdir- := compressed
|
||||||
|
|
||||||
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
|
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
|
||||||
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
|
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
|
||||||
|
@ -43,9 +43,17 @@ setup-y += video-vesa.o
|
||||||
setup-y += video-bios.o
|
setup-y += video-bios.o
|
||||||
|
|
||||||
targets += $(setup-y)
|
targets += $(setup-y)
|
||||||
hostprogs-y := tools/build
|
hostprogs-y := mkcpustr tools/build
|
||||||
|
|
||||||
HOSTCFLAGS_build.o := $(LINUXINCLUDE)
|
HOST_EXTRACFLAGS += $(LINUXINCLUDE)
|
||||||
|
|
||||||
|
$(obj)/cpu.o: $(obj)/cpustr.h
|
||||||
|
|
||||||
|
quiet_cmd_cpustr = CPUSTR $@
|
||||||
|
cmd_cpustr = $(obj)/mkcpustr > $@
|
||||||
|
targets += cpustr.h
|
||||||
|
$(obj)/cpustr.h: $(obj)/mkcpustr FORCE
|
||||||
|
$(call if_changed,cpustr)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -80,6 +88,7 @@ $(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
|
||||||
$(call if_changed,image)
|
$(call if_changed,image)
|
||||||
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
||||||
|
|
||||||
|
OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
|
||||||
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
|
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
|
||||||
$(call if_changed,objcopy)
|
$(call if_changed,objcopy)
|
||||||
|
|
||||||
|
@ -90,7 +99,6 @@ $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
|
||||||
$(call if_changed,ld)
|
$(call if_changed,ld)
|
||||||
|
|
||||||
OBJCOPYFLAGS_setup.bin := -O binary
|
OBJCOPYFLAGS_setup.bin := -O binary
|
||||||
|
|
||||||
$(obj)/setup.bin: $(obj)/setup.elf FORCE
|
$(obj)/setup.bin: $(obj)/setup.elf FORCE
|
||||||
$(call if_changed,objcopy)
|
$(call if_changed,objcopy)
|
||||||
|
|
||||||
|
@ -98,7 +106,7 @@ $(obj)/compressed/vmlinux: FORCE
|
||||||
$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
|
$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
|
||||||
|
|
||||||
# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
|
# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
|
||||||
FDARGS =
|
FDARGS =
|
||||||
# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
|
# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
|
||||||
FDINITRD =
|
FDINITRD =
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ $(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $
|
||||||
$(call if_changed,ld)
|
$(call if_changed,ld)
|
||||||
@:
|
@:
|
||||||
|
|
||||||
|
OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
|
||||||
$(obj)/vmlinux.bin: vmlinux FORCE
|
$(obj)/vmlinux.bin: vmlinux FORCE
|
||||||
$(call if_changed,objcopy)
|
$(call if_changed,objcopy)
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,8 @@ startup_32:
|
||||||
|
|
||||||
#ifdef CONFIG_RELOCATABLE
|
#ifdef CONFIG_RELOCATABLE
|
||||||
movl %ebp, %ebx
|
movl %ebp, %ebx
|
||||||
addl $(LARGE_PAGE_SIZE -1), %ebx
|
addl $(PMD_PAGE_SIZE -1), %ebx
|
||||||
andl $LARGE_PAGE_MASK, %ebx
|
andl $PMD_PAGE_MASK, %ebx
|
||||||
#else
|
#else
|
||||||
movl $CONFIG_PHYSICAL_START, %ebx
|
movl $CONFIG_PHYSICAL_START, %ebx
|
||||||
#endif
|
#endif
|
||||||
|
@ -220,8 +220,8 @@ ENTRY(startup_64)
|
||||||
/* Start with the delta to where the kernel will run at. */
|
/* Start with the delta to where the kernel will run at. */
|
||||||
#ifdef CONFIG_RELOCATABLE
|
#ifdef CONFIG_RELOCATABLE
|
||||||
leaq startup_32(%rip) /* - $startup_32 */, %rbp
|
leaq startup_32(%rip) /* - $startup_32 */, %rbp
|
||||||
addq $(LARGE_PAGE_SIZE - 1), %rbp
|
addq $(PMD_PAGE_SIZE - 1), %rbp
|
||||||
andq $LARGE_PAGE_MASK, %rbp
|
andq $PMD_PAGE_MASK, %rbp
|
||||||
movq %rbp, %rbx
|
movq %rbp, %rbx
|
||||||
#else
|
#else
|
||||||
movq $CONFIG_PHYSICAL_START, %rbp
|
movq $CONFIG_PHYSICAL_START, %rbp
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*- linux-c -*- ------------------------------------------------------- *
|
/* -*- linux-c -*- ------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
* Copyright 2007-2008 rPath, Inc. - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This file is part of the Linux kernel, and is made available under
|
* This file is part of the Linux kernel, and is made available under
|
||||||
* the terms of the GNU General Public License version 2.
|
* the terms of the GNU General Public License version 2.
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
* ----------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* arch/i386/boot/cpu.c
|
* arch/x86/boot/cpu.c
|
||||||
*
|
*
|
||||||
* Check for obligatory CPU features and abort if the features are not
|
* Check for obligatory CPU features and abort if the features are not
|
||||||
* present.
|
* present.
|
||||||
|
@ -19,6 +19,8 @@
|
||||||
#include "bitops.h"
|
#include "bitops.h"
|
||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
|
|
||||||
|
#include "cpustr.h"
|
||||||
|
|
||||||
static char *cpu_name(int level)
|
static char *cpu_name(int level)
|
||||||
{
|
{
|
||||||
static char buf[6];
|
static char buf[6];
|
||||||
|
@ -35,6 +37,7 @@ int validate_cpu(void)
|
||||||
{
|
{
|
||||||
u32 *err_flags;
|
u32 *err_flags;
|
||||||
int cpu_level, req_level;
|
int cpu_level, req_level;
|
||||||
|
const unsigned char *msg_strs;
|
||||||
|
|
||||||
check_cpu(&cpu_level, &req_level, &err_flags);
|
check_cpu(&cpu_level, &req_level, &err_flags);
|
||||||
|
|
||||||
|
@ -51,13 +54,26 @@ int validate_cpu(void)
|
||||||
puts("This kernel requires the following features "
|
puts("This kernel requires the following features "
|
||||||
"not present on the CPU:\n");
|
"not present on the CPU:\n");
|
||||||
|
|
||||||
|
msg_strs = (const unsigned char *)x86_cap_strs;
|
||||||
|
|
||||||
for (i = 0; i < NCAPINTS; i++) {
|
for (i = 0; i < NCAPINTS; i++) {
|
||||||
u32 e = err_flags[i];
|
u32 e = err_flags[i];
|
||||||
|
|
||||||
for (j = 0; j < 32; j++) {
|
for (j = 0; j < 32; j++) {
|
||||||
if (e & 1)
|
int n = (i << 5)+j;
|
||||||
printf("%d:%d ", i, j);
|
if (*msg_strs < n) {
|
||||||
|
/* Skip to the next string */
|
||||||
|
do {
|
||||||
|
msg_strs++;
|
||||||
|
} while (*msg_strs);
|
||||||
|
msg_strs++;
|
||||||
|
}
|
||||||
|
if (e & 1) {
|
||||||
|
if (*msg_strs == n && msg_strs[1])
|
||||||
|
printf("%s ", msg_strs+1);
|
||||||
|
else
|
||||||
|
printf("%d:%d ", i, j);
|
||||||
|
}
|
||||||
e >>= 1;
|
e >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
arch/x86/boot/mkcpustr.c
Normal file
49
arch/x86/boot/mkcpustr.c
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2008 rPath, Inc. - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This file is part of the Linux kernel, and is made available under
|
||||||
|
* the terms of the GNU General Public License version 2 or (at your
|
||||||
|
* option) any later version; incorporated herein by reference.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a host program to preprocess the CPU strings into a
|
||||||
|
* compact format suitable for the setup code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "../kernel/cpu/feature_names.c"
|
||||||
|
|
||||||
|
#if NCAPFLAGS > 8
|
||||||
|
# error "Need to adjust the boot code handling of CPUID strings"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
printf("static const char x86_cap_strs[] = \n");
|
||||||
|
|
||||||
|
for (i = 0; i < NCAPINTS*32; i++) {
|
||||||
|
str = x86_cap_flags[i];
|
||||||
|
|
||||||
|
if (i == NCAPINTS*32-1) {
|
||||||
|
/* The last entry must be unconditional; this
|
||||||
|
also consumes the compiler-added null character */
|
||||||
|
if (!str)
|
||||||
|
str = "";
|
||||||
|
printf("\t\"\\x%02x\"\"%s\"\n", i, str);
|
||||||
|
} else if (str) {
|
||||||
|
printf("#if REQUIRED_MASK%d & (1 << %d)\n"
|
||||||
|
"\t\"\\x%02x\"\"%s\\0\"\n"
|
||||||
|
"#endif\n",
|
||||||
|
i >> 5, i & 31, i, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\t;\n");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -37,7 +37,8 @@ obj-$(CONFIG_X86_MSR) += msr.o
|
||||||
obj-$(CONFIG_X86_CPUID) += cpuid.o
|
obj-$(CONFIG_X86_CPUID) += cpuid.o
|
||||||
obj-$(CONFIG_MICROCODE) += microcode.o
|
obj-$(CONFIG_MICROCODE) += microcode.o
|
||||||
obj-$(CONFIG_PCI) += early-quirks.o
|
obj-$(CONFIG_PCI) += early-quirks.o
|
||||||
obj-$(CONFIG_APM) += apm_32.o
|
apm-y := apm_32.o
|
||||||
|
obj-$(CONFIG_APM) += apm.o
|
||||||
obj-$(CONFIG_X86_SMP) += smp_$(BITS).o smpboot_$(BITS).o tsc_sync.o
|
obj-$(CONFIG_X86_SMP) += smp_$(BITS).o smpboot_$(BITS).o tsc_sync.o
|
||||||
obj-$(CONFIG_X86_32_SMP) += smpcommon_32.o
|
obj-$(CONFIG_X86_32_SMP) += smpcommon_32.o
|
||||||
obj-$(CONFIG_X86_64_SMP) += smp_64.o smpboot_64.o tsc_sync.o
|
obj-$(CONFIG_X86_64_SMP) += smp_64.o smpboot_64.o tsc_sync.o
|
||||||
|
@ -74,7 +75,8 @@ ifdef CONFIG_INPUT_PCSPKR
|
||||||
obj-y += pcspeaker.o
|
obj-y += pcspeaker.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_SCx200) += scx200_32.o
|
obj-$(CONFIG_SCx200) += scx200.o
|
||||||
|
scx200-y += scx200_32.o
|
||||||
|
|
||||||
###
|
###
|
||||||
# 64 bit specific files
|
# 64 bit specific files
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y := intel_cacheinfo.o addon_cpuid_features.o
|
obj-y := intel_cacheinfo.o addon_cpuid_features.o
|
||||||
|
obj-y += feature_names.o
|
||||||
|
|
||||||
obj-$(CONFIG_X86_32) += common.o proc.o bugs.o
|
obj-$(CONFIG_X86_32) += common.o proc.o bugs.o
|
||||||
obj-$(CONFIG_X86_32) += amd.o
|
obj-$(CONFIG_X86_32) += amd.o
|
||||||
|
|
|
@ -623,16 +623,6 @@ cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
|
||||||
* They will insert themselves into the cpu_devs structure.
|
* They will insert themselves into the cpu_devs structure.
|
||||||
* Then, when cpu_init() is called, we can just iterate over that array.
|
* Then, when cpu_init() is called, we can just iterate over that array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int intel_cpu_init(void);
|
|
||||||
extern int cyrix_init_cpu(void);
|
|
||||||
extern int nsc_init_cpu(void);
|
|
||||||
extern int amd_init_cpu(void);
|
|
||||||
extern int centaur_init_cpu(void);
|
|
||||||
extern int transmeta_init_cpu(void);
|
|
||||||
extern int nexgen_init_cpu(void);
|
|
||||||
extern int umc_init_cpu(void);
|
|
||||||
|
|
||||||
void __init early_cpu_init(void)
|
void __init early_cpu_init(void)
|
||||||
{
|
{
|
||||||
intel_cpu_init();
|
intel_cpu_init();
|
||||||
|
|
|
@ -27,3 +27,12 @@ extern void display_cacheinfo(struct cpuinfo_x86 *c);
|
||||||
extern void early_init_intel(struct cpuinfo_x86 *c);
|
extern void early_init_intel(struct cpuinfo_x86 *c);
|
||||||
extern void early_init_amd(struct cpuinfo_x86 *c);
|
extern void early_init_amd(struct cpuinfo_x86 *c);
|
||||||
|
|
||||||
|
/* Specific CPU type init functions */
|
||||||
|
int intel_cpu_init(void);
|
||||||
|
int amd_init_cpu(void);
|
||||||
|
int cyrix_init_cpu(void);
|
||||||
|
int nsc_init_cpu(void);
|
||||||
|
int centaur_init_cpu(void);
|
||||||
|
int transmeta_init_cpu(void);
|
||||||
|
int nexgen_init_cpu(void);
|
||||||
|
int umc_init_cpu(void);
|
||||||
|
|
83
arch/x86/kernel/cpu/feature_names.c
Normal file
83
arch/x86/kernel/cpu/feature_names.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Strings for the various x86 capability flags.
|
||||||
|
*
|
||||||
|
* This file must not contain any executable code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asm/cpufeature.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These flag bits must match the definitions in <asm/cpufeature.h>.
|
||||||
|
* NULL means this bit is undefined or reserved; either way it doesn't
|
||||||
|
* have meaning as far as Linux is concerned. Note that it's important
|
||||||
|
* to realize there is a difference between this table and CPUID -- if
|
||||||
|
* applications want to get the raw CPUID data, they should access
|
||||||
|
* /dev/cpu/<cpu_nr>/cpuid instead.
|
||||||
|
*/
|
||||||
|
const char * const x86_cap_flags[NCAPINTS*32] = {
|
||||||
|
/* Intel-defined */
|
||||||
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
||||||
|
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
|
||||||
|
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
|
||||||
|
"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
|
||||||
|
|
||||||
|
/* AMD-defined */
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
|
||||||
|
NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
|
||||||
|
"3dnowext", "3dnow",
|
||||||
|
|
||||||
|
/* Transmeta-defined */
|
||||||
|
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
/* Other (Linux-defined) */
|
||||||
|
"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
"constant_tsc", "up", NULL, "arch_perfmon",
|
||||||
|
"pebs", "bts", NULL, NULL,
|
||||||
|
"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
/* Intel-defined (#2) */
|
||||||
|
"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
|
||||||
|
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
|
||||||
|
NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
/* VIA/Cyrix/Centaur-defined */
|
||||||
|
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
|
||||||
|
"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
/* AMD-defined (#2) */
|
||||||
|
"lahf_lm", "cmp_legacy", "svm", "extapic",
|
||||||
|
"cr8_legacy", "abm", "sse4a", "misalignsse",
|
||||||
|
"3dnowprefetch", "osvw", "ibs", "sse5",
|
||||||
|
"skinit", "wdt", NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
/* Auxiliary (Linux-defined) */
|
||||||
|
"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const x86_power_flags[32] = {
|
||||||
|
"ts", /* temperature sensor */
|
||||||
|
"fid", /* frequency id control */
|
||||||
|
"vid", /* voltage id control */
|
||||||
|
"ttp", /* thermal trip */
|
||||||
|
"tm",
|
||||||
|
"stc",
|
||||||
|
"100mhzsteps",
|
||||||
|
"hwpstate",
|
||||||
|
"", /* tsc invariant mapped to constant_tsc */
|
||||||
|
/* nothing */
|
||||||
|
};
|
|
@ -13,6 +13,7 @@
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/ds.h>
|
#include <asm/ds.h>
|
||||||
|
#include <asm/bugs.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include <asm/processor-flags.h>
|
#include <asm/processor-flags.h>
|
||||||
#include "mtrr.h"
|
#include "mtrr.h"
|
||||||
|
|
||||||
int arr3_protected;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cyrix_get_arr(unsigned int reg, unsigned long *base,
|
cyrix_get_arr(unsigned int reg, unsigned long *base,
|
||||||
unsigned long *size, mtrr_type * type)
|
unsigned long *size, mtrr_type * type)
|
||||||
|
@ -99,8 +97,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
|
||||||
case 4:
|
case 4:
|
||||||
return replace_reg;
|
return replace_reg;
|
||||||
case 3:
|
case 3:
|
||||||
if (arr3_protected)
|
|
||||||
break;
|
|
||||||
case 2:
|
case 2:
|
||||||
case 1:
|
case 1:
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -115,8 +111,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
cyrix_get_arr(i, &lbase, &lsize, <ype);
|
cyrix_get_arr(i, &lbase, &lsize, <ype);
|
||||||
if ((i == 3) && arr3_protected)
|
|
||||||
continue;
|
|
||||||
if (lsize == 0)
|
if (lsize == 0)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -260,107 +254,6 @@ static void cyrix_set_all(void)
|
||||||
post_set();
|
post_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
|
|
||||||
* with the SMM (System Management Mode) mode. So we need the following:
|
|
||||||
* Check whether SMI_LOCK (CCR3 bit 0) is set
|
|
||||||
* if it is set, write a warning message: ARR3 cannot be changed!
|
|
||||||
* (it cannot be changed until the next processor reset)
|
|
||||||
* if it is reset, then we can change it, set all the needed bits:
|
|
||||||
* - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
|
|
||||||
* - disable access to SMM memory (CCR1 bit 2 reset)
|
|
||||||
* - disable SMM mode (CCR1 bit 1 reset)
|
|
||||||
* - disable write protection of ARR3 (CCR6 bit 1 reset)
|
|
||||||
* - (maybe) disable ARR3
|
|
||||||
* Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
|
|
||||||
*/
|
|
||||||
static void __init
|
|
||||||
cyrix_arr_init(void)
|
|
||||||
{
|
|
||||||
struct set_mtrr_context ctxt;
|
|
||||||
unsigned char ccr[7];
|
|
||||||
int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
int i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* flush cache and enable MAPEN */
|
|
||||||
set_mtrr_prepare_save(&ctxt);
|
|
||||||
set_mtrr_cache_disable(&ctxt);
|
|
||||||
|
|
||||||
/* Save all CCRs locally */
|
|
||||||
ccr[0] = getCx86(CX86_CCR0);
|
|
||||||
ccr[1] = getCx86(CX86_CCR1);
|
|
||||||
ccr[2] = getCx86(CX86_CCR2);
|
|
||||||
ccr[3] = ctxt.ccr3;
|
|
||||||
ccr[4] = getCx86(CX86_CCR4);
|
|
||||||
ccr[5] = getCx86(CX86_CCR5);
|
|
||||||
ccr[6] = getCx86(CX86_CCR6);
|
|
||||||
|
|
||||||
if (ccr[3] & 1) {
|
|
||||||
ccrc[3] = 1;
|
|
||||||
arr3_protected = 1;
|
|
||||||
} else {
|
|
||||||
/* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
|
|
||||||
* access to SMM memory through ARR3 (bit 7).
|
|
||||||
*/
|
|
||||||
if (ccr[1] & 0x80) {
|
|
||||||
ccr[1] &= 0x7f;
|
|
||||||
ccrc[1] |= 0x80;
|
|
||||||
}
|
|
||||||
if (ccr[1] & 0x04) {
|
|
||||||
ccr[1] &= 0xfb;
|
|
||||||
ccrc[1] |= 0x04;
|
|
||||||
}
|
|
||||||
if (ccr[1] & 0x02) {
|
|
||||||
ccr[1] &= 0xfd;
|
|
||||||
ccrc[1] |= 0x02;
|
|
||||||
}
|
|
||||||
arr3_protected = 0;
|
|
||||||
if (ccr[6] & 0x02) {
|
|
||||||
ccr[6] &= 0xfd;
|
|
||||||
ccrc[6] = 1; /* Disable write protection of ARR3 */
|
|
||||||
setCx86(CX86_CCR6, ccr[6]);
|
|
||||||
}
|
|
||||||
/* Disable ARR3. This is safe now that we disabled SMM. */
|
|
||||||
/* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
|
|
||||||
}
|
|
||||||
/* If we changed CCR1 in memory, change it in the processor, too. */
|
|
||||||
if (ccrc[1])
|
|
||||||
setCx86(CX86_CCR1, ccr[1]);
|
|
||||||
|
|
||||||
/* Enable ARR usage by the processor */
|
|
||||||
if (!(ccr[5] & 0x20)) {
|
|
||||||
ccr[5] |= 0x20;
|
|
||||||
ccrc[5] = 1;
|
|
||||||
setCx86(CX86_CCR5, ccr[5]);
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
for (i = 0; i < 7; i++)
|
|
||||||
ccr_state[i] = ccr[i];
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
cyrix_get_arr(i,
|
|
||||||
&arr_state[i].base, &arr_state[i].size,
|
|
||||||
&arr_state[i].type);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */
|
|
||||||
|
|
||||||
if (ccrc[5])
|
|
||||||
printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
|
|
||||||
if (ccrc[3])
|
|
||||||
printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
|
|
||||||
/*
|
|
||||||
if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
|
|
||||||
if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
|
|
||||||
if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
|
|
||||||
*/
|
|
||||||
if (ccrc[6])
|
|
||||||
printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct mtrr_ops cyrix_mtrr_ops = {
|
static struct mtrr_ops cyrix_mtrr_ops = {
|
||||||
.vendor = X86_VENDOR_CYRIX,
|
.vendor = X86_VENDOR_CYRIX,
|
||||||
// .init = cyrix_arr_init,
|
// .init = cyrix_arr_init,
|
||||||
|
|
|
@ -59,12 +59,6 @@ struct mtrr_ops * mtrr_if = NULL;
|
||||||
static void set_mtrr(unsigned int reg, unsigned long base,
|
static void set_mtrr(unsigned int reg, unsigned long base,
|
||||||
unsigned long size, mtrr_type type);
|
unsigned long size, mtrr_type type);
|
||||||
|
|
||||||
#ifndef CONFIG_X86_64
|
|
||||||
extern int arr3_protected;
|
|
||||||
#else
|
|
||||||
#define arr3_protected 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void set_mtrr_ops(struct mtrr_ops * ops)
|
void set_mtrr_ops(struct mtrr_ops * ops)
|
||||||
{
|
{
|
||||||
if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
|
if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
|
||||||
|
@ -513,12 +507,6 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
|
||||||
printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
|
printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (is_cpu(CYRIX) && !use_intel()) {
|
|
||||||
if ((reg == 3) && arr3_protected) {
|
|
||||||
printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mtrr_if->get(reg, &lbase, &lsize, <ype);
|
mtrr_if->get(reg, &lbase, &lsize, <ype);
|
||||||
if (lsize < 1) {
|
if (lsize < 1) {
|
||||||
printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
|
printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
|
||||||
|
@ -566,10 +554,6 @@ EXPORT_SYMBOL(mtrr_del);
|
||||||
* These should be called implicitly, but we can't yet until all the initcall
|
* These should be called implicitly, but we can't yet until all the initcall
|
||||||
* stuff is done...
|
* stuff is done...
|
||||||
*/
|
*/
|
||||||
extern void amd_init_mtrr(void);
|
|
||||||
extern void cyrix_init_mtrr(void);
|
|
||||||
extern void centaur_init_mtrr(void);
|
|
||||||
|
|
||||||
static void __init init_ifs(void)
|
static void __init init_ifs(void)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_X86_64
|
#ifndef CONFIG_X86_64
|
||||||
|
|
|
@ -97,3 +97,7 @@ void mtrr_state_warn(void);
|
||||||
const char *mtrr_attrib_to_str(int x);
|
const char *mtrr_attrib_to_str(int x);
|
||||||
void mtrr_wrmsr(unsigned, unsigned, unsigned);
|
void mtrr_wrmsr(unsigned, unsigned, unsigned);
|
||||||
|
|
||||||
|
/* CPU specific mtrr init functions */
|
||||||
|
int amd_init_mtrr(void);
|
||||||
|
int cyrix_init_mtrr(void);
|
||||||
|
int centaur_init_mtrr(void);
|
||||||
|
|
|
@ -10,80 +10,6 @@
|
||||||
*/
|
*/
|
||||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* These flag bits must match the definitions in <asm/cpufeature.h>.
|
|
||||||
* NULL means this bit is undefined or reserved; either way it doesn't
|
|
||||||
* have meaning as far as Linux is concerned. Note that it's important
|
|
||||||
* to realize there is a difference between this table and CPUID -- if
|
|
||||||
* applications want to get the raw CPUID data, they should access
|
|
||||||
* /dev/cpu/<cpu_nr>/cpuid instead.
|
|
||||||
*/
|
|
||||||
static const char * const x86_cap_flags[] = {
|
|
||||||
/* Intel-defined */
|
|
||||||
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
|
||||||
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
|
|
||||||
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
|
|
||||||
"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
|
|
||||||
|
|
||||||
/* AMD-defined */
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
|
|
||||||
NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
|
|
||||||
"3dnowext", "3dnow",
|
|
||||||
|
|
||||||
/* Transmeta-defined */
|
|
||||||
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Other (Linux-defined) */
|
|
||||||
"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
|
|
||||||
NULL, NULL, NULL, NULL,
|
|
||||||
"constant_tsc", "up", NULL, "arch_perfmon",
|
|
||||||
"pebs", "bts", NULL, "sync_rdtsc",
|
|
||||||
"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Intel-defined (#2) */
|
|
||||||
"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
|
|
||||||
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
|
|
||||||
NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* VIA/Cyrix/Centaur-defined */
|
|
||||||
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
|
|
||||||
"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* AMD-defined (#2) */
|
|
||||||
"lahf_lm", "cmp_legacy", "svm", "extapic",
|
|
||||||
"cr8_legacy", "abm", "sse4a", "misalignsse",
|
|
||||||
"3dnowprefetch", "osvw", "ibs", "sse5",
|
|
||||||
"skinit", "wdt", NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Auxiliary (Linux-defined) */
|
|
||||||
"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
};
|
|
||||||
static const char * const x86_power_flags[] = {
|
|
||||||
"ts", /* temperature sensor */
|
|
||||||
"fid", /* frequency id control */
|
|
||||||
"vid", /* voltage id control */
|
|
||||||
"ttp", /* thermal trip */
|
|
||||||
"tm",
|
|
||||||
"stc",
|
|
||||||
"100mhzsteps",
|
|
||||||
"hwpstate",
|
|
||||||
"", /* constant_tsc - moved to flags */
|
|
||||||
/* nothing */
|
|
||||||
};
|
|
||||||
struct cpuinfo_x86 *c = v;
|
struct cpuinfo_x86 *c = v;
|
||||||
int i, n = 0;
|
int i, n = 0;
|
||||||
int fpu_exception;
|
int fpu_exception;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2000 H. Peter Anvin - All Rights Reserved
|
* Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,6 +17,10 @@
|
||||||
* and then read in chunks of 16 bytes. A larger size means multiple
|
* and then read in chunks of 16 bytes. A larger size means multiple
|
||||||
* reads of consecutive levels.
|
* reads of consecutive levels.
|
||||||
*
|
*
|
||||||
|
* The lower 32 bits of the file position is used as the incoming %eax,
|
||||||
|
* and the upper 32 bits of the file position as the incoming %ecx,
|
||||||
|
* the latter intended for "counting" eax levels like eax=4.
|
||||||
|
*
|
||||||
* This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
|
* This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
|
||||||
* an SMP box will direct the access to CPU %d.
|
* an SMP box will direct the access to CPU %d.
|
||||||
*/
|
*/
|
||||||
|
@ -43,35 +47,24 @@
|
||||||
|
|
||||||
static struct class *cpuid_class;
|
static struct class *cpuid_class;
|
||||||
|
|
||||||
struct cpuid_command {
|
struct cpuid_regs {
|
||||||
u32 reg;
|
u32 eax, ebx, ecx, edx;
|
||||||
u32 *data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cpuid_smp_cpuid(void *cmd_block)
|
static void cpuid_smp_cpuid(void *cmd_block)
|
||||||
{
|
{
|
||||||
struct cpuid_command *cmd = cmd_block;
|
struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block;
|
||||||
|
|
||||||
cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2],
|
cpuid_count(cmd->eax, cmd->ecx,
|
||||||
&cmd->data[3]);
|
&cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
|
||||||
}
|
|
||||||
|
|
||||||
static inline void do_cpuid(int cpu, u32 reg, u32 * data)
|
|
||||||
{
|
|
||||||
struct cpuid_command cmd;
|
|
||||||
|
|
||||||
cmd.reg = reg;
|
|
||||||
cmd.data = data;
|
|
||||||
|
|
||||||
smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
|
static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
|
||||||
{
|
{
|
||||||
loff_t ret;
|
loff_t ret;
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
|
||||||
lock_kernel();
|
mutex_lock(&inode->i_mutex);
|
||||||
|
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
case 0:
|
case 0:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
|
@ -84,8 +77,7 @@ static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
unlock_kernel();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,19 +85,21 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
|
||||||
size_t count, loff_t * ppos)
|
size_t count, loff_t * ppos)
|
||||||
{
|
{
|
||||||
char __user *tmp = buf;
|
char __user *tmp = buf;
|
||||||
u32 data[4];
|
struct cpuid_regs cmd;
|
||||||
u32 reg = *ppos;
|
|
||||||
int cpu = iminor(file->f_path.dentry->d_inode);
|
int cpu = iminor(file->f_path.dentry->d_inode);
|
||||||
|
u64 pos = *ppos;
|
||||||
|
|
||||||
if (count % 16)
|
if (count % 16)
|
||||||
return -EINVAL; /* Invalid chunk size */
|
return -EINVAL; /* Invalid chunk size */
|
||||||
|
|
||||||
for (; count; count -= 16) {
|
for (; count; count -= 16) {
|
||||||
do_cpuid(cpu, reg, data);
|
cmd.eax = pos;
|
||||||
if (copy_to_user(tmp, &data, 16))
|
cmd.ecx = pos >> 32;
|
||||||
|
smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
|
||||||
|
if (copy_to_user(tmp, &cmd, 16))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
tmp += 16;
|
tmp += 16;
|
||||||
*ppos = reg++;
|
*ppos = ++pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp - buf;
|
return tmp - buf;
|
||||||
|
@ -193,7 +187,7 @@ static int __init cpuid_init(void)
|
||||||
}
|
}
|
||||||
for_each_online_cpu(i) {
|
for_each_online_cpu(i) {
|
||||||
err = cpuid_device_create(i);
|
err = cpuid_device_create(i);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
goto out_class;
|
goto out_class;
|
||||||
}
|
}
|
||||||
register_hotcpu_notifier(&cpuid_class_cpu_notifier);
|
register_hotcpu_notifier(&cpuid_class_cpu_notifier);
|
||||||
|
@ -208,7 +202,7 @@ static int __init cpuid_init(void)
|
||||||
}
|
}
|
||||||
class_destroy(cpuid_class);
|
class_destroy(cpuid_class);
|
||||||
out_chrdev:
|
out_chrdev:
|
||||||
unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
|
unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,11 +379,9 @@ void __init efi_init(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
|
|
||||||
static void __init runtime_code_page_mkexec(void)
|
static void __init runtime_code_page_mkexec(void)
|
||||||
{
|
{
|
||||||
efi_memory_desc_t *md;
|
efi_memory_desc_t *md;
|
||||||
unsigned long end;
|
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if (!(__supported_pte_mask & _PAGE_NX))
|
if (!(__supported_pte_mask & _PAGE_NX))
|
||||||
|
@ -392,18 +390,13 @@ static void __init runtime_code_page_mkexec(void)
|
||||||
/* Make EFI runtime service code area executable */
|
/* Make EFI runtime service code area executable */
|
||||||
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
||||||
md = p;
|
md = p;
|
||||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
|
|
||||||
if (md->type == EFI_RUNTIME_SERVICES_CODE &&
|
if (md->type != EFI_RUNTIME_SERVICES_CODE)
|
||||||
(end >> PAGE_SHIFT) <= max_pfn_mapped) {
|
continue;
|
||||||
set_memory_x(md->virt_addr, md->num_pages);
|
|
||||||
set_memory_uc(md->virt_addr, md->num_pages);
|
set_memory_x(md->virt_addr, md->num_pages << EFI_PAGE_SHIFT);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
__flush_tlb_all();
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static inline void __init runtime_code_page_mkexec(void) { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function will switch the EFI runtime services to virtual mode.
|
* This function will switch the EFI runtime services to virtual mode.
|
||||||
|
@ -417,30 +410,40 @@ void __init efi_enter_virtual_mode(void)
|
||||||
{
|
{
|
||||||
efi_memory_desc_t *md;
|
efi_memory_desc_t *md;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long end;
|
unsigned long size;
|
||||||
void *p;
|
u64 end, systab;
|
||||||
|
void *p, *va;
|
||||||
|
|
||||||
efi.systab = NULL;
|
efi.systab = NULL;
|
||||||
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
||||||
md = p;
|
md = p;
|
||||||
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
||||||
continue;
|
continue;
|
||||||
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
|
|
||||||
if ((md->attribute & EFI_MEMORY_WB) &&
|
size = md->num_pages << EFI_PAGE_SHIFT;
|
||||||
((end >> PAGE_SHIFT) <= max_pfn_mapped))
|
end = md->phys_addr + size;
|
||||||
md->virt_addr = (unsigned long)__va(md->phys_addr);
|
|
||||||
|
if ((end >> PAGE_SHIFT) <= max_pfn_mapped)
|
||||||
|
va = __va(md->phys_addr);
|
||||||
else
|
else
|
||||||
md->virt_addr = (unsigned long)
|
va = efi_ioremap(md->phys_addr, size);
|
||||||
efi_ioremap(md->phys_addr,
|
|
||||||
md->num_pages << EFI_PAGE_SHIFT);
|
if (md->attribute & EFI_MEMORY_WB)
|
||||||
if (!md->virt_addr)
|
set_memory_uc(md->virt_addr, size);
|
||||||
|
|
||||||
|
md->virt_addr = (u64) (unsigned long) va;
|
||||||
|
|
||||||
|
if (!va) {
|
||||||
printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
|
printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
|
||||||
(unsigned long long)md->phys_addr);
|
(unsigned long long)md->phys_addr);
|
||||||
if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
|
continue;
|
||||||
((unsigned long)efi_phys.systab < end))
|
}
|
||||||
efi.systab = (efi_system_table_t *)(unsigned long)
|
|
||||||
(md->virt_addr - md->phys_addr +
|
systab = (u64) (unsigned long) efi_phys.systab;
|
||||||
(unsigned long)efi_phys.systab);
|
if (md->phys_addr <= systab && systab < end) {
|
||||||
|
systab += md->virt_addr - md->phys_addr;
|
||||||
|
efi.systab = (efi_system_table_t *) (unsigned long) systab;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(!efi.systab);
|
BUG_ON(!efi.systab);
|
||||||
|
|
|
@ -54,10 +54,10 @@ static void __init early_mapping_set_exec(unsigned long start,
|
||||||
else
|
else
|
||||||
set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
|
set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
|
||||||
__supported_pte_mask));
|
__supported_pte_mask));
|
||||||
if (level == 4)
|
if (level == PG_LEVEL_4K)
|
||||||
start = (start + PMD_SIZE) & PMD_MASK;
|
|
||||||
else
|
|
||||||
start = (start + PAGE_SIZE) & PAGE_MASK;
|
start = (start + PAGE_SIZE) & PAGE_MASK;
|
||||||
|
else
|
||||||
|
start = (start + PMD_SIZE) & PMD_MASK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,23 +109,23 @@ void __init efi_reserve_bootmem(void)
|
||||||
memmap.nr_map * memmap.desc_size);
|
memmap.nr_map * memmap.desc_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __iomem * __init efi_ioremap(unsigned long offset,
|
void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
|
||||||
unsigned long size)
|
|
||||||
{
|
{
|
||||||
static unsigned pages_mapped;
|
static unsigned pages_mapped;
|
||||||
unsigned long last_addr;
|
|
||||||
unsigned i, pages;
|
unsigned i, pages;
|
||||||
|
|
||||||
last_addr = offset + size - 1;
|
/* phys_addr and size must be page aligned */
|
||||||
offset &= PAGE_MASK;
|
if ((phys_addr & ~PAGE_MASK) || (size & ~PAGE_MASK))
|
||||||
pages = (PAGE_ALIGN(last_addr) - offset) >> PAGE_SHIFT;
|
return NULL;
|
||||||
|
|
||||||
|
pages = size >> PAGE_SHIFT;
|
||||||
if (pages_mapped + pages > MAX_EFI_IO_PAGES)
|
if (pages_mapped + pages > MAX_EFI_IO_PAGES)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < pages; i++) {
|
for (i = 0; i < pages; i++) {
|
||||||
__set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
|
__set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
|
||||||
offset, PAGE_KERNEL_EXEC_NOCACHE);
|
phys_addr, PAGE_KERNEL);
|
||||||
offset += PAGE_SIZE;
|
phys_addr += PAGE_SIZE;
|
||||||
pages_mapped++;
|
pages_mapped++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ startup_64:
|
||||||
|
|
||||||
/* Is the address not 2M aligned? */
|
/* Is the address not 2M aligned? */
|
||||||
movq %rbp, %rax
|
movq %rbp, %rax
|
||||||
andl $~LARGE_PAGE_MASK, %eax
|
andl $~PMD_PAGE_MASK, %eax
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jnz bad_address
|
jnz bad_address
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ startup_64:
|
||||||
|
|
||||||
/* Add an Identity mapping if I am above 1G */
|
/* Add an Identity mapping if I am above 1G */
|
||||||
leaq _text(%rip), %rdi
|
leaq _text(%rip), %rdi
|
||||||
andq $LARGE_PAGE_MASK, %rdi
|
andq $PMD_PAGE_MASK, %rdi
|
||||||
|
|
||||||
movq %rdi, %rax
|
movq %rdi, %rax
|
||||||
shrq $PUD_SHIFT, %rax
|
shrq $PUD_SHIFT, %rax
|
||||||
|
|
|
@ -35,7 +35,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
|
||||||
if (mincount <= pc->size)
|
if (mincount <= pc->size)
|
||||||
return 0;
|
return 0;
|
||||||
oldsize = pc->size;
|
oldsize = pc->size;
|
||||||
mincount = (mincount + 511) & (~511);
|
mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) &
|
||||||
|
(~(PAGE_SIZE / LDT_ENTRY_SIZE - 1));
|
||||||
if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
|
if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
|
||||||
newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
|
newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2000 H. Peter Anvin - All Rights Reserved
|
* Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -45,9 +45,10 @@ static struct class *msr_class;
|
||||||
|
|
||||||
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
|
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
|
||||||
{
|
{
|
||||||
loff_t ret = -EINVAL;
|
loff_t ret;
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
|
||||||
lock_kernel();
|
mutex_lock(&inode->i_mutex);
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
case 0:
|
case 0:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
|
@ -56,8 +57,11 @@ static loff_t msr_seek(struct file *file, loff_t offset, int orig)
|
||||||
case 1:
|
case 1:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
ret = file->f_pos;
|
ret = file->f_pos;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
unlock_kernel();
|
mutex_unlock(&inode->i_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -501,7 +501,7 @@ static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
a = aper + iommu_size;
|
a = aper + iommu_size;
|
||||||
iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
|
iommu_size -= round_up(a, PMD_PAGE_SIZE) - a;
|
||||||
|
|
||||||
if (iommu_size < 64*1024*1024) {
|
if (iommu_size < 64*1024*1024) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
|
@ -731,7 +731,8 @@ void __init gart_iommu_init(void)
|
||||||
* the backing memory. The GART address is only used by PCI
|
* the backing memory. The GART address is only used by PCI
|
||||||
* devices.
|
* devices.
|
||||||
*/
|
*/
|
||||||
clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size);
|
set_memory_np((unsigned long)__va(iommu_bus_base),
|
||||||
|
iommu_size >> PAGE_SHIFT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to workaround a bug (thanks to BenH)
|
* Try to workaround a bug (thanks to BenH)
|
||||||
|
|
|
@ -251,7 +251,7 @@ void cpu_idle_wait(void)
|
||||||
* because it has nothing to do.
|
* because it has nothing to do.
|
||||||
* Give all the remaining CPUS a kick.
|
* Give all the remaining CPUS a kick.
|
||||||
*/
|
*/
|
||||||
smp_call_function_mask(map, do_nothing, 0, 0);
|
smp_call_function_mask(map, do_nothing, NULL, 0);
|
||||||
} while (!cpus_empty(map));
|
} while (!cpus_empty(map));
|
||||||
|
|
||||||
set_cpus_allowed(current, tmp);
|
set_cpus_allowed(current, tmp);
|
||||||
|
|
|
@ -1068,82 +1068,6 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||||
struct cpuinfo_x86 *c = v;
|
struct cpuinfo_x86 *c = v;
|
||||||
int cpu = 0, i;
|
int cpu = 0, i;
|
||||||
|
|
||||||
/*
|
|
||||||
* These flag bits must match the definitions in <asm/cpufeature.h>.
|
|
||||||
* NULL means this bit is undefined or reserved; either way it doesn't
|
|
||||||
* have meaning as far as Linux is concerned. Note that it's important
|
|
||||||
* to realize there is a difference between this table and CPUID -- if
|
|
||||||
* applications want to get the raw CPUID data, they should access
|
|
||||||
* /dev/cpu/<cpu_nr>/cpuid instead.
|
|
||||||
*/
|
|
||||||
static const char *const x86_cap_flags[] = {
|
|
||||||
/* Intel-defined */
|
|
||||||
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
|
||||||
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
|
|
||||||
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
|
|
||||||
"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
|
|
||||||
|
|
||||||
/* AMD-defined */
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
|
|
||||||
NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
|
|
||||||
"3dnowext", "3dnow",
|
|
||||||
|
|
||||||
/* Transmeta-defined */
|
|
||||||
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Other (Linux-defined) */
|
|
||||||
"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
|
|
||||||
NULL, NULL, NULL, NULL,
|
|
||||||
"constant_tsc", "up", NULL, "arch_perfmon",
|
|
||||||
"pebs", "bts", NULL, "sync_rdtsc",
|
|
||||||
"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Intel-defined (#2) */
|
|
||||||
"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
|
|
||||||
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
|
|
||||||
NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* VIA/Cyrix/Centaur-defined */
|
|
||||||
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
|
|
||||||
"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* AMD-defined (#2) */
|
|
||||||
"lahf_lm", "cmp_legacy", "svm", "extapic",
|
|
||||||
"cr8_legacy", "abm", "sse4a", "misalignsse",
|
|
||||||
"3dnowprefetch", "osvw", "ibs", "sse5",
|
|
||||||
"skinit", "wdt", NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
|
|
||||||
/* Auxiliary (Linux-defined) */
|
|
||||||
"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
};
|
|
||||||
static const char *const x86_power_flags[] = {
|
|
||||||
"ts", /* temperature sensor */
|
|
||||||
"fid", /* frequency id control */
|
|
||||||
"vid", /* voltage id control */
|
|
||||||
"ttp", /* thermal trip */
|
|
||||||
"tm",
|
|
||||||
"stc",
|
|
||||||
"100mhzsteps",
|
|
||||||
"hwpstate",
|
|
||||||
"", /* tsc invariant mapped to constant_tsc */
|
|
||||||
/* nothing */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
cpu = c->cpu_index;
|
cpu = c->cpu_index;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
|
||||||
extern int rodata_test_data;
|
extern int rodata_test_data;
|
||||||
|
|
||||||
|
@ -89,16 +90,7 @@ static noinline int test_address(void *address)
|
||||||
"2: mov %[zero], %[rslt]\n"
|
"2: mov %[zero], %[rslt]\n"
|
||||||
" ret\n"
|
" ret\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(0b,2b)
|
||||||
" .align 8\n"
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
" .long 0b\n"
|
|
||||||
" .long 2b\n"
|
|
||||||
#else
|
|
||||||
" .quad 0b\n"
|
|
||||||
" .quad 2b\n"
|
|
||||||
#endif
|
|
||||||
".previous\n"
|
|
||||||
: [rslt] "=r" (result)
|
: [rslt] "=r" (result)
|
||||||
: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
|
: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,12 +11,7 @@
|
||||||
* trampoline page to make our stack and everything else
|
* trampoline page to make our stack and everything else
|
||||||
* is a mystery.
|
* is a mystery.
|
||||||
*
|
*
|
||||||
* In fact we don't actually need a stack so we don't
|
* We jump into arch/x86/kernel/head_32.S.
|
||||||
* set one up.
|
|
||||||
*
|
|
||||||
* We jump into the boot/compressed/head.S code. So you'd
|
|
||||||
* better be running a compressed kernel image or you
|
|
||||||
* won't get very far.
|
|
||||||
*
|
*
|
||||||
* On entry to trampoline_data, the processor is in real mode
|
* On entry to trampoline_data, the processor is in real mode
|
||||||
* with 16-bit addressing and 16-bit data. CS has some value
|
* with 16-bit addressing and 16-bit data. CS has some value
|
||||||
|
|
|
@ -10,9 +10,6 @@
|
||||||
* trampoline page to make our stack and everything else
|
* trampoline page to make our stack and everything else
|
||||||
* is a mystery.
|
* is a mystery.
|
||||||
*
|
*
|
||||||
* In fact we don't actually need a stack so we don't
|
|
||||||
* set one up.
|
|
||||||
*
|
|
||||||
* On entry to trampoline_data, the processor is in real mode
|
* On entry to trampoline_data, the processor is in real mode
|
||||||
* with 16-bit addressing and 16-bit data. CS has some value
|
* with 16-bit addressing and 16-bit data. CS has some value
|
||||||
* and IP is zero. Thus, data addresses need to be absolute
|
* and IP is zero. Thus, data addresses need to be absolute
|
||||||
|
|
|
@ -220,21 +220,21 @@ static void vmi_set_tr(void)
|
||||||
static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
|
static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
|
||||||
{
|
{
|
||||||
u32 *idt_entry = (u32 *)g;
|
u32 *idt_entry = (u32 *)g;
|
||||||
vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]);
|
vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
|
static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
|
||||||
const void *desc, int type)
|
const void *desc, int type)
|
||||||
{
|
{
|
||||||
u32 *gdt_entry = (u32 *)desc;
|
u32 *gdt_entry = (u32 *)desc;
|
||||||
vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[2]);
|
vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
|
static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
|
||||||
const void *desc)
|
const void *desc)
|
||||||
{
|
{
|
||||||
u32 *ldt_entry = (u32 *)desc;
|
u32 *ldt_entry = (u32 *)desc;
|
||||||
vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[2]);
|
vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmi_load_sp0(struct tss_struct *tss,
|
static void vmi_load_sp0(struct tss_struct *tss,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
#include <asm/asm.h>
|
||||||
#include <asm/i387.h>
|
#include <asm/i387.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,10 +51,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
|
||||||
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from) );
|
: : "r" (from) );
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,10 +79,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
|
||||||
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from), "r" (to) : "memory");
|
: : "r" (from), "r" (to) : "memory");
|
||||||
from+=64;
|
from+=64;
|
||||||
to+=64;
|
to+=64;
|
||||||
|
@ -181,10 +176,7 @@ static void fast_copy_page(void *to, void *from)
|
||||||
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from) );
|
: : "r" (from) );
|
||||||
|
|
||||||
for(i=0; i<(4096-320)/64; i++)
|
for(i=0; i<(4096-320)/64; i++)
|
||||||
|
@ -211,10 +203,7 @@ static void fast_copy_page(void *to, void *from)
|
||||||
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from), "r" (to) : "memory");
|
: : "r" (from), "r" (to) : "memory");
|
||||||
from+=64;
|
from+=64;
|
||||||
to+=64;
|
to+=64;
|
||||||
|
@ -311,10 +300,7 @@ static void fast_copy_page(void *to, void *from)
|
||||||
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from) );
|
: : "r" (from) );
|
||||||
|
|
||||||
for(i=0; i<4096/64; i++)
|
for(i=0; i<4096/64; i++)
|
||||||
|
@ -341,10 +327,7 @@ static void fast_copy_page(void *to, void *from)
|
||||||
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 4\n"
|
|
||||||
" .long 1b, 3b\n"
|
|
||||||
".previous"
|
|
||||||
: : "r" (from), "r" (to) : "memory");
|
: : "r" (from), "r" (to) : "memory");
|
||||||
from+=64;
|
from+=64;
|
||||||
to+=64;
|
to+=64;
|
||||||
|
|
|
@ -48,10 +48,7 @@ do { \
|
||||||
"3: movl %5,%0\n" \
|
"3: movl %5,%0\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(0b,3b) \
|
||||||
" .align 4\n" \
|
|
||||||
" .long 0b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
|
: "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
|
||||||
"=&D" (__d2) \
|
"=&D" (__d2) \
|
||||||
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
|
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
|
||||||
|
@ -132,11 +129,8 @@ do { \
|
||||||
"3: lea 0(%2,%0,4),%0\n" \
|
"3: lea 0(%2,%0,4),%0\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(0b,3b) \
|
||||||
" .align 4\n" \
|
_ASM_EXTABLE(1b,2b) \
|
||||||
" .long 0b,3b\n" \
|
|
||||||
" .long 1b,2b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=&c"(size), "=&D" (__d0) \
|
: "=&c"(size), "=&D" (__d0) \
|
||||||
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
|
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -31,10 +31,7 @@ do { \
|
||||||
"3: movq %5,%0\n" \
|
"3: movq %5,%0\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(0b,3b) \
|
||||||
" .align 8\n" \
|
|
||||||
" .quad 0b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
|
: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
|
||||||
"=&D" (__d2) \
|
"=&D" (__d2) \
|
||||||
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
|
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
|
||||||
|
@ -87,11 +84,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
|
||||||
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
|
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(0b,3b)
|
||||||
" .align 8\n"
|
_ASM_EXTABLE(1b,2b)
|
||||||
" .quad 0b,3b\n"
|
|
||||||
" .quad 1b,2b\n"
|
|
||||||
".previous"
|
|
||||||
: [size8] "=c"(size), [dst] "=&D" (__d0)
|
: [size8] "=c"(size), [dst] "=&D" (__d0)
|
||||||
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
|
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
|
||||||
[zero] "r" (0UL), [eight] "r" (8UL));
|
[zero] "r" (0UL), [eight] "r" (8UL));
|
||||||
|
|
|
@ -240,7 +240,8 @@ void dump_pagetable(unsigned long address)
|
||||||
pud = pud_offset(pgd, address);
|
pud = pud_offset(pgd, address);
|
||||||
if (bad_address(pud)) goto bad;
|
if (bad_address(pud)) goto bad;
|
||||||
printk("PUD %lx ", pud_val(*pud));
|
printk("PUD %lx ", pud_val(*pud));
|
||||||
if (!pud_present(*pud)) goto ret;
|
if (!pud_present(*pud) || pud_large(*pud))
|
||||||
|
goto ret;
|
||||||
|
|
||||||
pmd = pmd_offset(pud, address);
|
pmd = pmd_offset(pud, address);
|
||||||
if (bad_address(pmd)) goto bad;
|
if (bad_address(pmd)) goto bad;
|
||||||
|
@ -508,6 +509,10 @@ static int vmalloc_fault(unsigned long address)
|
||||||
pmd_t *pmd, *pmd_ref;
|
pmd_t *pmd, *pmd_ref;
|
||||||
pte_t *pte, *pte_ref;
|
pte_t *pte, *pte_ref;
|
||||||
|
|
||||||
|
/* Make sure we are in vmalloc area */
|
||||||
|
if (!(address >= VMALLOC_START && address < VMALLOC_END))
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* Copy kernel mappings over when needed. This can also
|
/* Copy kernel mappings over when needed. This can also
|
||||||
happen within a race in page table update. In the later
|
happen within a race in page table update. In the later
|
||||||
case just flush. */
|
case just flush. */
|
||||||
|
@ -603,6 +608,9 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
if (unlikely(address >= TASK_SIZE)) {
|
if (unlikely(address >= TASK_SIZE)) {
|
||||||
|
#else
|
||||||
|
if (unlikely(address >= TASK_SIZE64)) {
|
||||||
|
#endif
|
||||||
if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
|
if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
|
||||||
vmalloc_fault(address) >= 0)
|
vmalloc_fault(address) >= 0)
|
||||||
return;
|
return;
|
||||||
|
@ -618,6 +626,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||||
goto bad_area_nosemaphore;
|
goto bad_area_nosemaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
/* It's safe to allow irq's after cr2 has been saved and the vmalloc
|
/* It's safe to allow irq's after cr2 has been saved and the vmalloc
|
||||||
fault has been handled. */
|
fault has been handled. */
|
||||||
if (regs->flags & (X86_EFLAGS_IF|VM_MASK))
|
if (regs->flags & (X86_EFLAGS_IF|VM_MASK))
|
||||||
|
@ -630,28 +640,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
||||||
if (in_atomic() || !mm)
|
if (in_atomic() || !mm)
|
||||||
goto bad_area_nosemaphore;
|
goto bad_area_nosemaphore;
|
||||||
#else /* CONFIG_X86_64 */
|
#else /* CONFIG_X86_64 */
|
||||||
if (unlikely(address >= TASK_SIZE64)) {
|
|
||||||
/*
|
|
||||||
* Don't check for the module range here: its PML4
|
|
||||||
* is always initialized because it's shared with the main
|
|
||||||
* kernel text. Only vmalloc may need PML4 syncups.
|
|
||||||
*/
|
|
||||||
if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
|
|
||||||
((address >= VMALLOC_START && address < VMALLOC_END))) {
|
|
||||||
if (vmalloc_fault(address) >= 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can handle a stale RO->RW TLB */
|
|
||||||
if (spurious_fault(address, error_code))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't take the mm semaphore here. If we fixup a prefetch
|
|
||||||
* fault we could otherwise deadlock.
|
|
||||||
*/
|
|
||||||
goto bad_area_nosemaphore;
|
|
||||||
}
|
|
||||||
if (likely(regs->flags & X86_EFLAGS_IF))
|
if (likely(regs->flags & X86_EFLAGS_IF))
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/initrd.h>
|
#include <linux/initrd.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
|
|
||||||
|
#include <asm/asm.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
@ -718,10 +719,7 @@ static noinline int do_test_wp_bit(void)
|
||||||
"1: movb %1, %0 \n"
|
"1: movb %1, %0 \n"
|
||||||
" xorl %2, %2 \n"
|
" xorl %2, %2 \n"
|
||||||
"2: \n"
|
"2: \n"
|
||||||
".section __ex_table, \"a\"\n"
|
_ASM_EXTABLE(1b,2b)
|
||||||
" .align 4 \n"
|
|
||||||
" .long 1b, 2b \n"
|
|
||||||
".previous \n"
|
|
||||||
:"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
|
:"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
|
||||||
"=q" (tmp_reg),
|
"=q" (tmp_reg),
|
||||||
"=r" (flag)
|
"=r" (flag)
|
||||||
|
|
|
@ -273,7 +273,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
|
||||||
int i = pmd_index(address);
|
int i = pmd_index(address);
|
||||||
|
|
||||||
for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
|
for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
|
||||||
unsigned long entry;
|
|
||||||
pmd_t *pmd = pmd_page + pmd_index(address);
|
pmd_t *pmd = pmd_page + pmd_index(address);
|
||||||
|
|
||||||
if (address >= end) {
|
if (address >= end) {
|
||||||
|
@ -287,9 +286,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
|
||||||
if (pmd_val(*pmd))
|
if (pmd_val(*pmd))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
entry = __PAGE_KERNEL_LARGE|_PAGE_GLOBAL|address;
|
set_pte((pte_t *)pmd,
|
||||||
entry &= __supported_pte_mask;
|
pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
|
||||||
set_pmd(pmd, __pmd(entry));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,49 +432,6 @@ void __init paging_init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Unmap a kernel mapping if it exists. This is useful to avoid
|
|
||||||
* prefetches from the CPU leading to inconsistent cache lines.
|
|
||||||
* address and size must be aligned to 2MB boundaries.
|
|
||||||
* Does nothing when the mapping doesn't exist.
|
|
||||||
*/
|
|
||||||
void __init clear_kernel_mapping(unsigned long address, unsigned long size)
|
|
||||||
{
|
|
||||||
unsigned long end = address + size;
|
|
||||||
|
|
||||||
BUG_ON(address & ~LARGE_PAGE_MASK);
|
|
||||||
BUG_ON(size & ~LARGE_PAGE_MASK);
|
|
||||||
|
|
||||||
for (; address < end; address += LARGE_PAGE_SIZE) {
|
|
||||||
pgd_t *pgd = pgd_offset_k(address);
|
|
||||||
pud_t *pud;
|
|
||||||
pmd_t *pmd;
|
|
||||||
|
|
||||||
if (pgd_none(*pgd))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pud = pud_offset(pgd, address);
|
|
||||||
if (pud_none(*pud))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pmd = pmd_offset(pud, address);
|
|
||||||
if (!pmd || pmd_none(*pmd))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!(pmd_val(*pmd) & _PAGE_PSE)) {
|
|
||||||
/*
|
|
||||||
* Could handle this, but it should not happen
|
|
||||||
* currently:
|
|
||||||
*/
|
|
||||||
printk(KERN_ERR "clear_kernel_mapping: "
|
|
||||||
"mapping has been split. will leak memory\n");
|
|
||||||
pmd_ERROR(*pmd);
|
|
||||||
}
|
|
||||||
set_pmd(pmd, __pmd(0));
|
|
||||||
}
|
|
||||||
__flush_tlb_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Memory hotplug specific functions
|
* Memory hotplug specific functions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -70,25 +70,12 @@ int page_is_ram(unsigned long pagenr)
|
||||||
* Fix up the linear direct mapping of the kernel to avoid cache attribute
|
* Fix up the linear direct mapping of the kernel to avoid cache attribute
|
||||||
* conflicts.
|
* conflicts.
|
||||||
*/
|
*/
|
||||||
static int ioremap_change_attr(unsigned long paddr, unsigned long size,
|
static int ioremap_change_attr(unsigned long vaddr, unsigned long size,
|
||||||
enum ioremap_mode mode)
|
enum ioremap_mode mode)
|
||||||
{
|
{
|
||||||
unsigned long vaddr = (unsigned long)__va(paddr);
|
|
||||||
unsigned long nrpages = size >> PAGE_SHIFT;
|
unsigned long nrpages = size >> PAGE_SHIFT;
|
||||||
unsigned int level;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* No change for pages after the last mapping */
|
|
||||||
if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is no identity map for this address,
|
|
||||||
* change_page_attr_addr is unnecessary
|
|
||||||
*/
|
|
||||||
if (!lookup_address(vaddr, &level))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case IOR_MODE_UNCACHED:
|
case IOR_MODE_UNCACHED:
|
||||||
default:
|
default:
|
||||||
|
@ -114,9 +101,8 @@ static int ioremap_change_attr(unsigned long paddr, unsigned long size,
|
||||||
static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
|
static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
|
||||||
enum ioremap_mode mode)
|
enum ioremap_mode mode)
|
||||||
{
|
{
|
||||||
void __iomem *addr;
|
unsigned long pfn, offset, last_addr, vaddr;
|
||||||
struct vm_struct *area;
|
struct vm_struct *area;
|
||||||
unsigned long offset, last_addr;
|
|
||||||
pgprot_t prot;
|
pgprot_t prot;
|
||||||
|
|
||||||
/* Don't allow wraparound or zero size */
|
/* Don't allow wraparound or zero size */
|
||||||
|
@ -133,9 +119,10 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
|
||||||
/*
|
/*
|
||||||
* Don't allow anybody to remap normal RAM that we're using..
|
* Don't allow anybody to remap normal RAM that we're using..
|
||||||
*/
|
*/
|
||||||
for (offset = phys_addr >> PAGE_SHIFT; offset < max_pfn_mapped &&
|
for (pfn = phys_addr >> PAGE_SHIFT; pfn < max_pfn_mapped &&
|
||||||
(offset << PAGE_SHIFT) < last_addr; offset++) {
|
(pfn << PAGE_SHIFT) < last_addr; pfn++) {
|
||||||
if (page_is_ram(offset))
|
if (page_is_ram(pfn) && pfn_valid(pfn) &&
|
||||||
|
!PageReserved(pfn_to_page(pfn)))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,19 +150,18 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
|
||||||
if (!area)
|
if (!area)
|
||||||
return NULL;
|
return NULL;
|
||||||
area->phys_addr = phys_addr;
|
area->phys_addr = phys_addr;
|
||||||
addr = (void __iomem *) area->addr;
|
vaddr = (unsigned long) area->addr;
|
||||||
if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
|
if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
|
||||||
phys_addr, prot)) {
|
remove_vm_area((void *)(vaddr & PAGE_MASK));
|
||||||
remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioremap_change_attr(phys_addr, size, mode) < 0) {
|
if (ioremap_change_attr(vaddr, size, mode) < 0) {
|
||||||
vunmap(addr);
|
vunmap(area->addr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (void __iomem *) (offset + (char __iomem *)addr);
|
return (void __iomem *) (vaddr + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,9 +240,6 @@ void iounmap(volatile void __iomem *addr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the direct mapping. Can block */
|
|
||||||
ioremap_change_attr(p->phys_addr, p->size, IOR_MODE_CACHED);
|
|
||||||
|
|
||||||
/* Finally remove it */
|
/* Finally remove it */
|
||||||
o = remove_vm_area((void *)addr);
|
o = remove_vm_area((void *)addr);
|
||||||
BUG_ON(p != o || o == NULL);
|
BUG_ON(p != o || o == NULL);
|
||||||
|
|
|
@ -202,6 +202,8 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
|
||||||
if (node_data[nodeid] == NULL)
|
if (node_data[nodeid] == NULL)
|
||||||
return;
|
return;
|
||||||
nodedata_phys = __pa(node_data[nodeid]);
|
nodedata_phys = __pa(node_data[nodeid]);
|
||||||
|
printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
|
||||||
|
nodedata_phys + pgdat_size - 1);
|
||||||
|
|
||||||
memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
|
memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
|
||||||
NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
|
NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
|
||||||
|
@ -225,12 +227,15 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bootmap_start = __pa(bootmap);
|
bootmap_start = __pa(bootmap);
|
||||||
Dprintk("bootmap start %lu pages %lu\n", bootmap_start, bootmap_pages);
|
|
||||||
|
|
||||||
bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
|
bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
|
||||||
bootmap_start >> PAGE_SHIFT,
|
bootmap_start >> PAGE_SHIFT,
|
||||||
start_pfn, end_pfn);
|
start_pfn, end_pfn);
|
||||||
|
|
||||||
|
printk(KERN_INFO " bootmap [%016lx - %016lx] pages %lx\n",
|
||||||
|
bootmap_start, bootmap_start + bootmap_size - 1,
|
||||||
|
bootmap_pages);
|
||||||
|
|
||||||
free_bootmem_with_active_regions(nodeid, end);
|
free_bootmem_with_active_regions(nodeid, end);
|
||||||
|
|
||||||
reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
|
reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
|
||||||
|
|
|
@ -137,7 +137,8 @@ static __init int exercise_pageattr(void)
|
||||||
|
|
||||||
for (k = 0; k < len[i]; k++) {
|
for (k = 0; k < len[i]; k++) {
|
||||||
pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
|
pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
|
||||||
if (!pte || pgprot_val(pte_pgprot(*pte)) == 0) {
|
if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
|
||||||
|
!(pte_val(*pte) & _PAGE_PRESENT)) {
|
||||||
addr[i] = 0;
|
addr[i] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,17 @@
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The current flushing context - we pass it instead of 5 arguments:
|
||||||
|
*/
|
||||||
|
struct cpa_data {
|
||||||
|
unsigned long vaddr;
|
||||||
|
pgprot_t mask_set;
|
||||||
|
pgprot_t mask_clr;
|
||||||
|
int numpages;
|
||||||
|
int flushtlb;
|
||||||
|
};
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
within(unsigned long addr, unsigned long start, unsigned long end)
|
within(unsigned long addr, unsigned long start, unsigned long end)
|
||||||
{
|
{
|
||||||
|
@ -52,21 +63,23 @@ void clflush_cache_range(void *vaddr, unsigned int size)
|
||||||
|
|
||||||
static void __cpa_flush_all(void *arg)
|
static void __cpa_flush_all(void *arg)
|
||||||
{
|
{
|
||||||
|
unsigned long cache = (unsigned long)arg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush all to work around Errata in early athlons regarding
|
* Flush all to work around Errata in early athlons regarding
|
||||||
* large page flushing.
|
* large page flushing.
|
||||||
*/
|
*/
|
||||||
__flush_tlb_all();
|
__flush_tlb_all();
|
||||||
|
|
||||||
if (boot_cpu_data.x86_model >= 4)
|
if (cache && boot_cpu_data.x86_model >= 4)
|
||||||
wbinvd();
|
wbinvd();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpa_flush_all(void)
|
static void cpa_flush_all(unsigned long cache)
|
||||||
{
|
{
|
||||||
BUG_ON(irqs_disabled());
|
BUG_ON(irqs_disabled());
|
||||||
|
|
||||||
on_each_cpu(__cpa_flush_all, NULL, 1, 1);
|
on_each_cpu(__cpa_flush_all, (void *) cache, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpa_flush_range(void *arg)
|
static void __cpa_flush_range(void *arg)
|
||||||
|
@ -79,7 +92,7 @@ static void __cpa_flush_range(void *arg)
|
||||||
__flush_tlb_all();
|
__flush_tlb_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpa_flush_range(unsigned long start, int numpages)
|
static void cpa_flush_range(unsigned long start, int numpages, int cache)
|
||||||
{
|
{
|
||||||
unsigned int i, level;
|
unsigned int i, level;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
@ -89,6 +102,9 @@ static void cpa_flush_range(unsigned long start, int numpages)
|
||||||
|
|
||||||
on_each_cpu(__cpa_flush_range, NULL, 1, 1);
|
on_each_cpu(__cpa_flush_range, NULL, 1, 1);
|
||||||
|
|
||||||
|
if (!cache)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only need to flush on one CPU,
|
* We only need to flush on one CPU,
|
||||||
* clflush is a MESI-coherent instruction that
|
* clflush is a MESI-coherent instruction that
|
||||||
|
@ -101,11 +117,27 @@ static void cpa_flush_range(unsigned long start, int numpages)
|
||||||
/*
|
/*
|
||||||
* Only flush present addresses:
|
* Only flush present addresses:
|
||||||
*/
|
*/
|
||||||
if (pte && pte_present(*pte))
|
if (pte && (pte_val(*pte) & _PAGE_PRESENT))
|
||||||
clflush_cache_range((void *) addr, PAGE_SIZE);
|
clflush_cache_range((void *) addr, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HIGH_MAP_START __START_KERNEL_map
|
||||||
|
#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts a virtual address to a X86-64 highmap address
|
||||||
|
*/
|
||||||
|
static unsigned long virt_to_highmap(void *address)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
|
||||||
|
#else
|
||||||
|
return (unsigned long)address;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Certain areas of memory on x86 require very specific protection flags,
|
* Certain areas of memory on x86 require very specific protection flags,
|
||||||
* for example the BIOS area or kernel text. Callers don't always get this
|
* for example the BIOS area or kernel text. Callers don't always get this
|
||||||
|
@ -129,12 +161,24 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
|
||||||
*/
|
*/
|
||||||
if (within(address, (unsigned long)_text, (unsigned long)_etext))
|
if (within(address, (unsigned long)_text, (unsigned long)_etext))
|
||||||
pgprot_val(forbidden) |= _PAGE_NX;
|
pgprot_val(forbidden) |= _PAGE_NX;
|
||||||
|
/*
|
||||||
|
* Do the same for the x86-64 high kernel mapping
|
||||||
|
*/
|
||||||
|
if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
|
||||||
|
pgprot_val(forbidden) |= _PAGE_NX;
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RODATA
|
#ifdef CONFIG_DEBUG_RODATA
|
||||||
/* The .rodata section needs to be read-only */
|
/* The .rodata section needs to be read-only */
|
||||||
if (within(address, (unsigned long)__start_rodata,
|
if (within(address, (unsigned long)__start_rodata,
|
||||||
(unsigned long)__end_rodata))
|
(unsigned long)__end_rodata))
|
||||||
pgprot_val(forbidden) |= _PAGE_RW;
|
pgprot_val(forbidden) |= _PAGE_RW;
|
||||||
|
/*
|
||||||
|
* Do the same for the x86-64 high kernel mapping
|
||||||
|
*/
|
||||||
|
if (within(address, virt_to_highmap(__start_rodata),
|
||||||
|
virt_to_highmap(__end_rodata)))
|
||||||
|
pgprot_val(forbidden) |= _PAGE_RW;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
|
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
|
||||||
|
@ -142,6 +186,14 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
|
||||||
return prot;
|
return prot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup the page table entry for a virtual address. Return a pointer
|
||||||
|
* to the entry and the level of the mapping.
|
||||||
|
*
|
||||||
|
* Note: We return pud and pmd either when the entry is marked large
|
||||||
|
* or when the present bit is not set. Otherwise we would return a
|
||||||
|
* pointer to a nonexisting mapping.
|
||||||
|
*/
|
||||||
pte_t *lookup_address(unsigned long address, int *level)
|
pte_t *lookup_address(unsigned long address, int *level)
|
||||||
{
|
{
|
||||||
pgd_t *pgd = pgd_offset_k(address);
|
pgd_t *pgd = pgd_offset_k(address);
|
||||||
|
@ -152,21 +204,31 @@ pte_t *lookup_address(unsigned long address, int *level)
|
||||||
|
|
||||||
if (pgd_none(*pgd))
|
if (pgd_none(*pgd))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pud = pud_offset(pgd, address);
|
pud = pud_offset(pgd, address);
|
||||||
if (pud_none(*pud))
|
if (pud_none(*pud))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
*level = PG_LEVEL_1G;
|
||||||
|
if (pud_large(*pud) || !pud_present(*pud))
|
||||||
|
return (pte_t *)pud;
|
||||||
|
|
||||||
pmd = pmd_offset(pud, address);
|
pmd = pmd_offset(pud, address);
|
||||||
if (pmd_none(*pmd))
|
if (pmd_none(*pmd))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*level = PG_LEVEL_2M;
|
*level = PG_LEVEL_2M;
|
||||||
if (pmd_large(*pmd))
|
if (pmd_large(*pmd) || !pmd_present(*pmd))
|
||||||
return (pte_t *)pmd;
|
return (pte_t *)pmd;
|
||||||
|
|
||||||
*level = PG_LEVEL_4K;
|
*level = PG_LEVEL_4K;
|
||||||
|
|
||||||
return pte_offset_kernel(pmd, address);
|
return pte_offset_kernel(pmd, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the new pmd in all the pgds we know about:
|
||||||
|
*/
|
||||||
static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
|
static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
|
||||||
{
|
{
|
||||||
/* change init_mm */
|
/* change init_mm */
|
||||||
|
@ -175,6 +237,7 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
|
||||||
if (!SHARED_KERNEL_PMD) {
|
if (!SHARED_KERNEL_PMD) {
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
|
address = __pa(address);
|
||||||
list_for_each_entry(page, &pgd_list, lru) {
|
list_for_each_entry(page, &pgd_list, lru) {
|
||||||
pgd_t *pgd;
|
pgd_t *pgd;
|
||||||
pud_t *pud;
|
pud_t *pud;
|
||||||
|
@ -189,18 +252,114 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
try_preserve_large_page(pte_t *kpte, unsigned long address,
|
||||||
|
struct cpa_data *cpa)
|
||||||
|
{
|
||||||
|
unsigned long nextpage_addr, numpages, pmask, psize, flags;
|
||||||
|
pte_t new_pte, old_pte, *tmp;
|
||||||
|
pgprot_t old_prot, new_prot;
|
||||||
|
int level, do_split = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An Athlon 64 X2 showed hard hangs if we tried to preserve
|
||||||
|
* largepages and changed the PSE entry from RW to RO.
|
||||||
|
*
|
||||||
|
* As AMD CPUs have a long series of erratas in this area,
|
||||||
|
* (and none of the known ones seem to explain this hang),
|
||||||
|
* disable this code until the hang can be debugged:
|
||||||
|
*/
|
||||||
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&pgd_lock, flags);
|
||||||
|
/*
|
||||||
|
* Check for races, another CPU might have split this page
|
||||||
|
* up already:
|
||||||
|
*/
|
||||||
|
tmp = lookup_address(address, &level);
|
||||||
|
if (tmp != kpte)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case PG_LEVEL_2M:
|
||||||
|
psize = PMD_PAGE_SIZE;
|
||||||
|
pmask = PMD_PAGE_MASK;
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
case PG_LEVEL_1G:
|
||||||
|
psize = PMD_PAGE_SIZE;
|
||||||
|
pmask = PMD_PAGE_MASK;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
do_split = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the number of pages, which fit into this large
|
||||||
|
* page starting at address:
|
||||||
|
*/
|
||||||
|
nextpage_addr = (address + psize) & pmask;
|
||||||
|
numpages = (nextpage_addr - address) >> PAGE_SHIFT;
|
||||||
|
if (numpages < cpa->numpages)
|
||||||
|
cpa->numpages = numpages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are safe now. Check whether the new pgprot is the same:
|
||||||
|
*/
|
||||||
|
old_pte = *kpte;
|
||||||
|
old_prot = new_prot = pte_pgprot(old_pte);
|
||||||
|
|
||||||
|
pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
|
||||||
|
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
|
||||||
|
new_prot = static_protections(new_prot, address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are no changes, return. maxpages has been updated
|
||||||
|
* above:
|
||||||
|
*/
|
||||||
|
if (pgprot_val(new_prot) == pgprot_val(old_prot)) {
|
||||||
|
do_split = 0;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to change the attributes. Check, whether we can
|
||||||
|
* change the large page in one go. We request a split, when
|
||||||
|
* the address is not aligned and the number of pages is
|
||||||
|
* smaller than the number of pages in the large page. Note
|
||||||
|
* that we limited the number of possible pages already to
|
||||||
|
* the number of pages in the large page.
|
||||||
|
*/
|
||||||
|
if (address == (nextpage_addr - psize) && cpa->numpages == numpages) {
|
||||||
|
/*
|
||||||
|
* The address is aligned and the number of pages
|
||||||
|
* covers the full page.
|
||||||
|
*/
|
||||||
|
new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
|
||||||
|
__set_pmd_pte(kpte, address, new_pte);
|
||||||
|
cpa->flushtlb = 1;
|
||||||
|
do_split = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||||
|
|
||||||
|
return do_split;
|
||||||
|
}
|
||||||
|
|
||||||
static int split_large_page(pte_t *kpte, unsigned long address)
|
static int split_large_page(pte_t *kpte, unsigned long address)
|
||||||
{
|
{
|
||||||
pgprot_t ref_prot = pte_pgprot(pte_clrhuge(*kpte));
|
unsigned long flags, pfn, pfninc = 1;
|
||||||
gfp_t gfp_flags = GFP_KERNEL;
|
gfp_t gfp_flags = GFP_KERNEL;
|
||||||
unsigned long flags;
|
|
||||||
unsigned long addr;
|
|
||||||
pte_t *pbase, *tmp;
|
|
||||||
struct page *base;
|
|
||||||
unsigned int i, level;
|
unsigned int i, level;
|
||||||
|
pte_t *pbase, *tmp;
|
||||||
|
pgprot_t ref_prot;
|
||||||
|
struct page *base;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
gfp_flags = __GFP_HIGH | __GFP_NOFAIL | __GFP_NOWARN;
|
|
||||||
gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
|
gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
|
||||||
#endif
|
#endif
|
||||||
base = alloc_pages(gfp_flags, 0);
|
base = alloc_pages(gfp_flags, 0);
|
||||||
|
@ -213,30 +372,41 @@ static int split_large_page(pte_t *kpte, unsigned long address)
|
||||||
* up for us already:
|
* up for us already:
|
||||||
*/
|
*/
|
||||||
tmp = lookup_address(address, &level);
|
tmp = lookup_address(address, &level);
|
||||||
if (tmp != kpte) {
|
if (tmp != kpte)
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
|
||||||
|
|
||||||
address = __pa(address);
|
|
||||||
addr = address & LARGE_PAGE_MASK;
|
|
||||||
pbase = (pte_t *)page_address(base);
|
pbase = (pte_t *)page_address(base);
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
paravirt_alloc_pt(&init_mm, page_to_pfn(base));
|
paravirt_alloc_pt(&init_mm, page_to_pfn(base));
|
||||||
#endif
|
#endif
|
||||||
|
ref_prot = pte_pgprot(pte_clrhuge(*kpte));
|
||||||
|
|
||||||
pgprot_val(ref_prot) &= ~_PAGE_NX;
|
#ifdef CONFIG_X86_64
|
||||||
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE)
|
if (level == PG_LEVEL_1G) {
|
||||||
set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT, ref_prot));
|
pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT;
|
||||||
|
pgprot_val(ref_prot) |= _PAGE_PSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Install the new, split up pagetable. Important detail here:
|
* Get the target pfn from the original entry:
|
||||||
|
*/
|
||||||
|
pfn = pte_pfn(*kpte);
|
||||||
|
for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
|
||||||
|
set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install the new, split up pagetable. Important details here:
|
||||||
*
|
*
|
||||||
* On Intel the NX bit of all levels must be cleared to make a
|
* On Intel the NX bit of all levels must be cleared to make a
|
||||||
* page executable. See section 4.13.2 of Intel 64 and IA-32
|
* page executable. See section 4.13.2 of Intel 64 and IA-32
|
||||||
* Architectures Software Developer's Manual).
|
* Architectures Software Developer's Manual).
|
||||||
|
*
|
||||||
|
* Mark the entry present. The current mapping might be
|
||||||
|
* set to not present, which we preserved above.
|
||||||
*/
|
*/
|
||||||
ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
|
ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
|
||||||
|
pgprot_val(ref_prot) |= _PAGE_PRESENT;
|
||||||
__set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
|
__set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
|
||||||
base = NULL;
|
base = NULL;
|
||||||
|
|
||||||
|
@ -249,18 +419,12 @@ static int split_large_page(pte_t *kpte, unsigned long address)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
|
||||||
__change_page_attr(unsigned long address, unsigned long pfn,
|
|
||||||
pgprot_t mask_set, pgprot_t mask_clr)
|
|
||||||
{
|
{
|
||||||
|
int level, do_split, err;
|
||||||
struct page *kpte_page;
|
struct page *kpte_page;
|
||||||
int level, err = 0;
|
|
||||||
pte_t *kpte;
|
pte_t *kpte;
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
BUG_ON(pfn > max_low_pfn);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
repeat:
|
repeat:
|
||||||
kpte = lookup_address(address, &level);
|
kpte = lookup_address(address, &level);
|
||||||
if (!kpte)
|
if (!kpte)
|
||||||
|
@ -271,23 +435,62 @@ __change_page_attr(unsigned long address, unsigned long pfn,
|
||||||
BUG_ON(PageCompound(kpte_page));
|
BUG_ON(PageCompound(kpte_page));
|
||||||
|
|
||||||
if (level == PG_LEVEL_4K) {
|
if (level == PG_LEVEL_4K) {
|
||||||
pgprot_t new_prot = pte_pgprot(*kpte);
|
|
||||||
pte_t new_pte, old_pte = *kpte;
|
pte_t new_pte, old_pte = *kpte;
|
||||||
|
pgprot_t new_prot = pte_pgprot(old_pte);
|
||||||
|
|
||||||
pgprot_val(new_prot) &= ~pgprot_val(mask_clr);
|
if(!pte_val(old_pte)) {
|
||||||
pgprot_val(new_prot) |= pgprot_val(mask_set);
|
printk(KERN_WARNING "CPA: called for zero pte. "
|
||||||
|
"vaddr = %lx cpa->vaddr = %lx\n", address,
|
||||||
|
cpa->vaddr);
|
||||||
|
WARN_ON(1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
|
||||||
|
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
|
||||||
|
|
||||||
new_prot = static_protections(new_prot, address);
|
new_prot = static_protections(new_prot, address);
|
||||||
|
|
||||||
new_pte = pfn_pte(pfn, canon_pgprot(new_prot));
|
/*
|
||||||
BUG_ON(pte_pfn(new_pte) != pte_pfn(old_pte));
|
* We need to keep the pfn from the existing PTE,
|
||||||
|
* after all we're only going to change it's attributes
|
||||||
|
* not the memory it points to
|
||||||
|
*/
|
||||||
|
new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
|
||||||
|
|
||||||
set_pte_atomic(kpte, new_pte);
|
/*
|
||||||
} else {
|
* Do we really change anything ?
|
||||||
err = split_large_page(kpte, address);
|
*/
|
||||||
if (!err)
|
if (pte_val(old_pte) != pte_val(new_pte)) {
|
||||||
goto repeat;
|
set_pte_atomic(kpte, new_pte);
|
||||||
|
cpa->flushtlb = 1;
|
||||||
|
}
|
||||||
|
cpa->numpages = 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check, whether we can keep the large page intact
|
||||||
|
* and just change the pte:
|
||||||
|
*/
|
||||||
|
do_split = try_preserve_large_page(kpte, address, cpa);
|
||||||
|
/*
|
||||||
|
* When the range fits into the existing large page,
|
||||||
|
* return. cp->numpages and cpa->tlbflush have been updated in
|
||||||
|
* try_large_page:
|
||||||
|
*/
|
||||||
|
if (do_split <= 0)
|
||||||
|
return do_split;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to split the large page:
|
||||||
|
*/
|
||||||
|
err = split_large_page(kpte, address);
|
||||||
|
if (!err) {
|
||||||
|
cpa->flushtlb = 1;
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,19 +507,14 @@ __change_page_attr(unsigned long address, unsigned long pfn,
|
||||||
*
|
*
|
||||||
* Modules and drivers should use the set_memory_* APIs instead.
|
* Modules and drivers should use the set_memory_* APIs instead.
|
||||||
*/
|
*/
|
||||||
|
static int change_page_attr_addr(struct cpa_data *cpa)
|
||||||
#define HIGH_MAP_START __START_KERNEL_map
|
|
||||||
#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
|
|
||||||
|
|
||||||
static int
|
|
||||||
change_page_attr_addr(unsigned long address, pgprot_t mask_set,
|
|
||||||
pgprot_t mask_clr)
|
|
||||||
{
|
{
|
||||||
unsigned long phys_addr = __pa(address);
|
|
||||||
unsigned long pfn = phys_addr >> PAGE_SHIFT;
|
|
||||||
int err;
|
int err;
|
||||||
|
unsigned long address = cpa->vaddr;
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
unsigned long phys_addr = __pa(address);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are inside the high mapped kernel range, then we
|
* If we are inside the high mapped kernel range, then we
|
||||||
* fixup the low mapping first. __va() returns the virtual
|
* fixup the low mapping first. __va() returns the virtual
|
||||||
|
@ -326,7 +524,7 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
|
||||||
address = (unsigned long) __va(phys_addr);
|
address = (unsigned long) __va(phys_addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
err = __change_page_attr(address, pfn, mask_set, mask_clr);
|
err = __change_page_attr(address, cpa);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -339,42 +537,89 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
|
||||||
/*
|
/*
|
||||||
* Calc the high mapping address. See __phys_addr()
|
* Calc the high mapping address. See __phys_addr()
|
||||||
* for the non obvious details.
|
* for the non obvious details.
|
||||||
|
*
|
||||||
|
* Note that NX and other required permissions are
|
||||||
|
* checked in static_protections().
|
||||||
*/
|
*/
|
||||||
address = phys_addr + HIGH_MAP_START - phys_base;
|
address = phys_addr + HIGH_MAP_START - phys_base;
|
||||||
/* Make sure the kernel mappings stay executable */
|
|
||||||
pgprot_val(mask_clr) |= _PAGE_NX;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our high aliases are imprecise, because we check
|
* Our high aliases are imprecise, because we check
|
||||||
* everything between 0 and KERNEL_TEXT_SIZE, so do
|
* everything between 0 and KERNEL_TEXT_SIZE, so do
|
||||||
* not propagate lookup failures back to users:
|
* not propagate lookup failures back to users:
|
||||||
*/
|
*/
|
||||||
__change_page_attr(address, pfn, mask_set, mask_clr);
|
__change_page_attr(address, cpa);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __change_page_attr_set_clr(unsigned long addr, int numpages,
|
static int __change_page_attr_set_clr(struct cpa_data *cpa)
|
||||||
pgprot_t mask_set, pgprot_t mask_clr)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
int ret, numpages = cpa->numpages;
|
||||||
int ret;
|
|
||||||
|
|
||||||
for (i = 0; i < numpages ; i++, addr += PAGE_SIZE) {
|
while (numpages) {
|
||||||
ret = change_page_attr_addr(addr, mask_set, mask_clr);
|
/*
|
||||||
|
* Store the remaining nr of pages for the large page
|
||||||
|
* preservation check.
|
||||||
|
*/
|
||||||
|
cpa->numpages = numpages;
|
||||||
|
ret = change_page_attr_addr(cpa);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust the number of pages with the result of the
|
||||||
|
* CPA operation. Either a large page has been
|
||||||
|
* preserved or a single page update happened.
|
||||||
|
*/
|
||||||
|
BUG_ON(cpa->numpages > numpages);
|
||||||
|
numpages -= cpa->numpages;
|
||||||
|
cpa->vaddr += cpa->numpages * PAGE_SIZE;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int cache_attr(pgprot_t attr)
|
||||||
|
{
|
||||||
|
return pgprot_val(attr) &
|
||||||
|
(_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
|
||||||
|
}
|
||||||
|
|
||||||
static int change_page_attr_set_clr(unsigned long addr, int numpages,
|
static int change_page_attr_set_clr(unsigned long addr, int numpages,
|
||||||
pgprot_t mask_set, pgprot_t mask_clr)
|
pgprot_t mask_set, pgprot_t mask_clr)
|
||||||
{
|
{
|
||||||
int ret = __change_page_attr_set_clr(addr, numpages, mask_set,
|
struct cpa_data cpa;
|
||||||
mask_clr);
|
int ret, cache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check, if we are requested to change a not supported
|
||||||
|
* feature:
|
||||||
|
*/
|
||||||
|
mask_set = canon_pgprot(mask_set);
|
||||||
|
mask_clr = canon_pgprot(mask_clr);
|
||||||
|
if (!pgprot_val(mask_set) && !pgprot_val(mask_clr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cpa.vaddr = addr;
|
||||||
|
cpa.numpages = numpages;
|
||||||
|
cpa.mask_set = mask_set;
|
||||||
|
cpa.mask_clr = mask_clr;
|
||||||
|
cpa.flushtlb = 0;
|
||||||
|
|
||||||
|
ret = __change_page_attr_set_clr(&cpa);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether we really changed something:
|
||||||
|
*/
|
||||||
|
if (!cpa.flushtlb)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No need to flush, when we did not set any of the caching
|
||||||
|
* attributes:
|
||||||
|
*/
|
||||||
|
cache = cache_attr(mask_set);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On success we use clflush, when the CPU supports it to
|
* On success we use clflush, when the CPU supports it to
|
||||||
|
@ -383,9 +628,9 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
|
||||||
* wbindv):
|
* wbindv):
|
||||||
*/
|
*/
|
||||||
if (!ret && cpu_has_clflush)
|
if (!ret && cpu_has_clflush)
|
||||||
cpa_flush_range(addr, numpages);
|
cpa_flush_range(addr, numpages, cache);
|
||||||
else
|
else
|
||||||
cpa_flush_all();
|
cpa_flush_all(cache);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -489,37 +734,26 @@ int set_pages_rw(struct page *page, int numpages)
|
||||||
return set_memory_rw(addr, numpages);
|
return set_memory_rw(addr, numpages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_CPA_DEBUG)
|
|
||||||
static inline int __change_page_attr_set(unsigned long addr, int numpages,
|
|
||||||
pgprot_t mask)
|
|
||||||
{
|
|
||||||
return __change_page_attr_set_clr(addr, numpages, mask, __pgprot(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int __change_page_attr_clear(unsigned long addr, int numpages,
|
|
||||||
pgprot_t mask)
|
|
||||||
{
|
|
||||||
return __change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
|
|
||||||
static int __set_pages_p(struct page *page, int numpages)
|
static int __set_pages_p(struct page *page, int numpages)
|
||||||
{
|
{
|
||||||
unsigned long addr = (unsigned long)page_address(page);
|
struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
|
||||||
|
.numpages = numpages,
|
||||||
|
.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
|
||||||
|
.mask_clr = __pgprot(0)};
|
||||||
|
|
||||||
return __change_page_attr_set(addr, numpages,
|
return __change_page_attr_set_clr(&cpa);
|
||||||
__pgprot(_PAGE_PRESENT | _PAGE_RW));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __set_pages_np(struct page *page, int numpages)
|
static int __set_pages_np(struct page *page, int numpages)
|
||||||
{
|
{
|
||||||
unsigned long addr = (unsigned long)page_address(page);
|
struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
|
||||||
|
.numpages = numpages,
|
||||||
|
.mask_set = __pgprot(0),
|
||||||
|
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
|
||||||
|
|
||||||
return __change_page_attr_clear(addr, numpages,
|
return __change_page_attr_set_clr(&cpa);
|
||||||
__pgprot(_PAGE_PRESENT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kernel_map_pages(struct page *page, int numpages, int enable)
|
void kernel_map_pages(struct page *page, int numpages, int enable)
|
||||||
|
|
|
@ -219,50 +219,39 @@ static inline void pgd_list_del(pgd_t *pgd)
|
||||||
list_del(&page->lru);
|
list_del(&page->lru);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UNSHARED_PTRS_PER_PGD \
|
||||||
|
(SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
|
||||||
|
|
||||||
|
static void pgd_ctor(void *p)
|
||||||
#if (PTRS_PER_PMD == 1)
|
|
||||||
/* Non-PAE pgd constructor */
|
|
||||||
static void pgd_ctor(void *pgd)
|
|
||||||
{
|
{
|
||||||
|
pgd_t *pgd = p;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* !PAE, no pagetable sharing */
|
/* Clear usermode parts of PGD */
|
||||||
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
|
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
|
||||||
|
|
||||||
spin_lock_irqsave(&pgd_lock, flags);
|
spin_lock_irqsave(&pgd_lock, flags);
|
||||||
|
|
||||||
/* must happen under lock */
|
/* If the pgd points to a shared pagetable level (either the
|
||||||
clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
|
ptes in non-PAE, or shared PMD in PAE), then just copy the
|
||||||
swapper_pg_dir + USER_PTRS_PER_PGD,
|
references from swapper_pg_dir. */
|
||||||
KERNEL_PGD_PTRS);
|
if (PAGETABLE_LEVELS == 2 ||
|
||||||
paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
|
(PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
|
||||||
__pa(swapper_pg_dir) >> PAGE_SHIFT,
|
clone_pgd_range(pgd + USER_PTRS_PER_PGD,
|
||||||
USER_PTRS_PER_PGD,
|
|
||||||
KERNEL_PGD_PTRS);
|
|
||||||
pgd_list_add(pgd);
|
|
||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
|
||||||
}
|
|
||||||
#else /* PTRS_PER_PMD > 1 */
|
|
||||||
/* PAE pgd constructor */
|
|
||||||
static void pgd_ctor(void *pgd)
|
|
||||||
{
|
|
||||||
/* PAE, kernel PMD may be shared */
|
|
||||||
|
|
||||||
if (SHARED_KERNEL_PMD) {
|
|
||||||
clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
|
|
||||||
swapper_pg_dir + USER_PTRS_PER_PGD,
|
swapper_pg_dir + USER_PTRS_PER_PGD,
|
||||||
KERNEL_PGD_PTRS);
|
KERNEL_PGD_PTRS);
|
||||||
} else {
|
paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
|
||||||
unsigned long flags;
|
__pa(swapper_pg_dir) >> PAGE_SHIFT,
|
||||||
|
USER_PTRS_PER_PGD,
|
||||||
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
|
KERNEL_PGD_PTRS);
|
||||||
spin_lock_irqsave(&pgd_lock, flags);
|
|
||||||
pgd_list_add(pgd);
|
|
||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* list required to sync kernel mapping updates */
|
||||||
|
if (!SHARED_KERNEL_PMD)
|
||||||
|
pgd_list_add(pgd);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||||
}
|
}
|
||||||
#endif /* PTRS_PER_PMD */
|
|
||||||
|
|
||||||
static void pgd_dtor(void *pgd)
|
static void pgd_dtor(void *pgd)
|
||||||
{
|
{
|
||||||
|
@ -276,9 +265,6 @@ static void pgd_dtor(void *pgd)
|
||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UNSHARED_PTRS_PER_PGD \
|
|
||||||
(SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
#ifdef CONFIG_X86_PAE
|
||||||
/*
|
/*
|
||||||
* Mop up any pmd pages which may still be attached to the pgd.
|
* Mop up any pmd pages which may still be attached to the pgd.
|
||||||
|
@ -387,13 +373,6 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
|
||||||
|
|
||||||
void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
|
void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
|
||||||
{
|
{
|
||||||
/* This is called just after the pmd has been detached from
|
|
||||||
the pgd, which requires a full tlb flush to be recognized
|
|
||||||
by the CPU. Rather than incurring multiple tlb flushes
|
|
||||||
while the address space is being pulled down, make the tlb
|
|
||||||
gathering machinery do a full flush when we're done. */
|
|
||||||
tlb->fullmm = 1;
|
|
||||||
|
|
||||||
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
|
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
|
||||||
tlb_remove_page(tlb, virt_to_page(pmd));
|
tlb_remove_page(tlb, virt_to_page(pmd));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,36 +5,62 @@
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/nodemask.h>
|
#include <linux/nodemask.h>
|
||||||
|
#include <mach_apic.h>
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
|
#define XQUAD_PORTIO_BASE 0xfe400000
|
||||||
|
#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
|
||||||
|
|
||||||
#define BUS2QUAD(global) (mp_bus_id_to_node[global])
|
#define BUS2QUAD(global) (mp_bus_id_to_node[global])
|
||||||
#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
|
#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
|
||||||
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
|
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
|
||||||
|
|
||||||
|
extern void *xquad_portio; /* Where the IO area was mapped */
|
||||||
|
#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
|
||||||
|
|
||||||
#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
|
#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
|
||||||
(0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
|
(0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
|
||||||
|
|
||||||
|
static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
|
||||||
|
{
|
||||||
|
unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
|
||||||
|
if (xquad_portio)
|
||||||
|
writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
|
||||||
|
else
|
||||||
|
outl(val, 0xCF8);
|
||||||
|
}
|
||||||
|
|
||||||
static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
|
static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 *value)
|
unsigned int devfn, int reg, int len, u32 *value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
|
||||||
|
|
||||||
if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
|
if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_irqsave(&pci_config_lock, flags);
|
spin_lock_irqsave(&pci_config_lock, flags);
|
||||||
|
|
||||||
outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
|
write_cf8(bus, devfn, reg);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
*value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
*value = readb(adr + (reg & 3));
|
||||||
|
else
|
||||||
|
*value = inb(0xCFC + (reg & 3));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
*value = readw(adr + (reg & 2));
|
||||||
|
else
|
||||||
|
*value = inw(0xCFC + (reg & 2));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
*value = inl_quad(0xCFC, BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
*value = readl(adr);
|
||||||
|
else
|
||||||
|
*value = inl(0xCFC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,23 +73,33 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 value)
|
unsigned int devfn, int reg, int len, u32 value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
|
||||||
|
|
||||||
if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
|
if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_irqsave(&pci_config_lock, flags);
|
spin_lock_irqsave(&pci_config_lock, flags);
|
||||||
|
|
||||||
outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
|
write_cf8(bus, devfn, reg);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
writeb(value, adr + (reg & 3));
|
||||||
|
else
|
||||||
|
outb((u8)value, 0xCFC + (reg & 3));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
writew(value, adr + (reg & 2));
|
||||||
|
else
|
||||||
|
outw((u16)value, 0xCFC + (reg & 2));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
|
if (xquad_portio)
|
||||||
|
writel(value, adr + reg);
|
||||||
|
else
|
||||||
|
outl((u32)value, 0xCFC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,10 +35,11 @@
|
||||||
static inline unsigned char rtc_is_updating(void)
|
static inline unsigned char rtc_is_updating(void)
|
||||||
{
|
{
|
||||||
unsigned char uip;
|
unsigned char uip;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irq(&rtc_lock);
|
spin_lock_irqsave(&rtc_lock, flags);
|
||||||
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
|
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
|
||||||
spin_unlock_irq(&rtc_lock);
|
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||||
return uip;
|
return uip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +47,8 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
{
|
{
|
||||||
unsigned long uip_watchdog = jiffies;
|
unsigned long uip_watchdog = jiffies;
|
||||||
unsigned char ctrl;
|
unsigned char ctrl;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef CONFIG_MACH_DECSTATION
|
#ifdef CONFIG_MACH_DECSTATION
|
||||||
unsigned int real_year;
|
unsigned int real_year;
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,7 +75,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
|
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
|
||||||
* by the RTC when initially set to a non-zero value.
|
* by the RTC when initially set to a non-zero value.
|
||||||
*/
|
*/
|
||||||
spin_lock_irq(&rtc_lock);
|
spin_lock_irqsave(&rtc_lock, flags);
|
||||||
time->tm_sec = CMOS_READ(RTC_SECONDS);
|
time->tm_sec = CMOS_READ(RTC_SECONDS);
|
||||||
time->tm_min = CMOS_READ(RTC_MINUTES);
|
time->tm_min = CMOS_READ(RTC_MINUTES);
|
||||||
time->tm_hour = CMOS_READ(RTC_HOURS);
|
time->tm_hour = CMOS_READ(RTC_HOURS);
|
||||||
|
@ -83,7 +86,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
real_year = CMOS_READ(RTC_DEC_YEAR);
|
real_year = CMOS_READ(RTC_DEC_YEAR);
|
||||||
#endif
|
#endif
|
||||||
ctrl = CMOS_READ(RTC_CONTROL);
|
ctrl = CMOS_READ(RTC_CONTROL);
|
||||||
spin_unlock_irq(&rtc_lock);
|
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||||
|
|
||||||
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#define _ASM_GENERIC__TLB_H
|
#define _ASM_GENERIC__TLB_H
|
||||||
|
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/quicklist.h>
|
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
|
|
||||||
|
|
|
@ -29,4 +29,11 @@
|
||||||
|
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
|
/* Exception table entry */
|
||||||
|
# define _ASM_EXTABLE(from,to) \
|
||||||
|
" .section __ex_table,\"a\"\n" \
|
||||||
|
_ASM_ALIGN "\n" \
|
||||||
|
_ASM_PTR #from "," #to "\n" \
|
||||||
|
" .previous\n"
|
||||||
|
|
||||||
#endif /* _ASM_X86_ASM_H */
|
#endif /* _ASM_X86_ASM_H */
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
#define _ASM_X86_BUGS_H
|
#define _ASM_X86_BUGS_H
|
||||||
|
|
||||||
extern void check_bugs(void);
|
extern void check_bugs(void);
|
||||||
extern int ppro_with_ram_bug(void);
|
int ppro_with_ram_bug(void);
|
||||||
|
|
||||||
#endif /* _ASM_X86_BUGS_H */
|
#endif /* _ASM_X86_BUGS_H */
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
#ifndef _ASM_X86_CPUFEATURE_H
|
#ifndef _ASM_X86_CPUFEATURE_H
|
||||||
#define _ASM_X86_CPUFEATURE_H
|
#define _ASM_X86_CPUFEATURE_H
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#endif
|
|
||||||
#include <asm/required-features.h>
|
#include <asm/required-features.h>
|
||||||
|
|
||||||
#define NCAPINTS 8 /* N 32-bit words worth of info */
|
#define NCAPINTS 8 /* N 32-bit words worth of info */
|
||||||
|
@ -49,6 +46,7 @@
|
||||||
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
|
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
|
||||||
#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
|
#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
|
||||||
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
|
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
|
||||||
|
#define X86_FEATURE_GBPAGES (1*32+26) /* GB pages */
|
||||||
#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
|
#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
|
||||||
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
|
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
|
||||||
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
|
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
|
||||||
|
@ -115,6 +113,13 @@
|
||||||
*/
|
*/
|
||||||
#define X86_FEATURE_IDA (7*32+ 0) /* Intel Dynamic Acceleration */
|
#define X86_FEATURE_IDA (7*32+ 0) /* Intel Dynamic Acceleration */
|
||||||
|
|
||||||
|
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
extern const char * const x86_cap_flags[NCAPINTS*32];
|
||||||
|
extern const char * const x86_power_flags[32];
|
||||||
|
|
||||||
#define cpu_has(c, bit) \
|
#define cpu_has(c, bit) \
|
||||||
(__builtin_constant_p(bit) && \
|
(__builtin_constant_p(bit) && \
|
||||||
( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \
|
( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \
|
||||||
|
@ -175,6 +180,7 @@
|
||||||
#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
|
#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
|
||||||
#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
|
#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
|
||||||
#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
|
#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
|
||||||
|
#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)
|
||||||
|
|
||||||
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
||||||
# define cpu_has_invlpg 1
|
# define cpu_has_invlpg 1
|
||||||
|
@ -204,4 +210,6 @@
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
|
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
|
||||||
|
|
||||||
#endif /* _ASM_X86_CPUFEATURE_H */
|
#endif /* _ASM_X86_CPUFEATURE_H */
|
||||||
|
|
|
@ -33,7 +33,7 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
|
||||||
#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
|
#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
|
||||||
efi_call_virt(f, a1, a2, a3, a4, a5, a6)
|
efi_call_virt(f, a1, a2, a3, a4, a5, a6)
|
||||||
|
|
||||||
#define efi_ioremap(addr, size) ioremap(addr, size)
|
#define efi_ioremap(addr, size) ioremap_cache(addr, size)
|
||||||
|
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
|
||||||
efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
|
||||||
(u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
|
(u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
|
||||||
|
|
||||||
extern void *efi_ioremap(unsigned long offset, unsigned long size);
|
extern void *efi_ioremap(unsigned long addr, unsigned long size);
|
||||||
|
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,8 @@
|
||||||
"2: .section .fixup,\"ax\"\n \
|
"2: .section .fixup,\"ax\"\n \
|
||||||
3: mov %3, %1\n \
|
3: mov %3, %1\n \
|
||||||
jmp 2b\n \
|
jmp 2b\n \
|
||||||
.previous\n \
|
.previous\n" \
|
||||||
.section __ex_table,\"a\"\n \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
.align 8\n" \
|
|
||||||
_ASM_PTR "1b,3b\n \
|
|
||||||
.previous" \
|
|
||||||
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
|
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
|
||||||
: "i" (-EFAULT), "0" (oparg), "1" (0))
|
: "i" (-EFAULT), "0" (oparg), "1" (0))
|
||||||
|
|
||||||
|
@ -35,11 +32,9 @@
|
||||||
3: .section .fixup,\"ax\"\n \
|
3: .section .fixup,\"ax\"\n \
|
||||||
4: mov %5, %1\n \
|
4: mov %5, %1\n \
|
||||||
jmp 3b\n \
|
jmp 3b\n \
|
||||||
.previous\n \
|
.previous\n" \
|
||||||
.section __ex_table,\"a\"\n \
|
_ASM_EXTABLE(1b,4b) \
|
||||||
.align 8\n" \
|
_ASM_EXTABLE(2b,4b) \
|
||||||
_ASM_PTR "1b,4b,2b,4b\n \
|
|
||||||
.previous" \
|
|
||||||
: "=&a" (oldval), "=&r" (ret), "+m" (*uaddr), \
|
: "=&a" (oldval), "=&r" (ret), "+m" (*uaddr), \
|
||||||
"=&r" (tem) \
|
"=&r" (tem) \
|
||||||
: "r" (oparg), "i" (-EFAULT), "1" (0))
|
: "r" (oparg), "i" (-EFAULT), "1" (0))
|
||||||
|
@ -111,18 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
|
|
||||||
"1: lock; cmpxchgl %3, %1 \n"
|
"1: lock; cmpxchgl %3, %1 \n"
|
||||||
"2: .section .fixup, \"ax\" \n"
|
"2: .section .fixup, \"ax\" \n"
|
||||||
"3: mov %2, %0 \n"
|
"3: mov %2, %0 \n"
|
||||||
" jmp 2b \n"
|
" jmp 2b \n"
|
||||||
" .previous \n"
|
" .previous \n"
|
||||||
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .section __ex_table, \"a\" \n"
|
|
||||||
" .align 8 \n"
|
|
||||||
_ASM_PTR " 1b,3b \n"
|
|
||||||
" .previous \n"
|
|
||||||
|
|
||||||
: "=a" (oldval), "+m" (*uaddr)
|
: "=a" (oldval), "+m" (*uaddr)
|
||||||
: "i" (-EFAULT), "r" (newval), "0" (oldval)
|
: "i" (-EFAULT), "r" (newval), "0" (oldval)
|
||||||
: "memory"
|
: "memory"
|
||||||
|
|
|
@ -63,8 +63,8 @@ extern pte_t *pkmap_page_table;
|
||||||
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
|
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
|
||||||
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
|
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
|
||||||
|
|
||||||
extern void * FASTCALL(kmap_high(struct page *page));
|
extern void *kmap_high(struct page *page);
|
||||||
extern void FASTCALL(kunmap_high(struct page *page));
|
extern void kunmap_high(struct page *page);
|
||||||
|
|
||||||
void *kmap(struct page *page);
|
void *kmap(struct page *page);
|
||||||
void kunmap(struct page *page);
|
void kunmap(struct page *page);
|
||||||
|
|
|
@ -47,7 +47,7 @@ void enable_8259A_irq(unsigned int irq);
|
||||||
int i8259A_irq_pending(unsigned int irq);
|
int i8259A_irq_pending(unsigned int irq);
|
||||||
void make_8259A_irq(unsigned int irq);
|
void make_8259A_irq(unsigned int irq);
|
||||||
void init_8259A(int aeoi);
|
void init_8259A(int aeoi);
|
||||||
void FASTCALL(send_IPI_self(int vector));
|
void send_IPI_self(int vector);
|
||||||
void init_VISWS_APIC_irqs(void);
|
void init_VISWS_APIC_irqs(void);
|
||||||
void setup_IO_APIC(void);
|
void setup_IO_APIC(void);
|
||||||
void disable_IO_APIC(void);
|
void disable_IO_APIC(void);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
#include <linux/regset.h>
|
#include <linux/regset.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/sigcontext.h>
|
#include <asm/sigcontext.h>
|
||||||
#include <asm/user.h>
|
#include <asm/user.h>
|
||||||
|
@ -41,10 +42,7 @@ static inline void tolerant_fwait(void)
|
||||||
{
|
{
|
||||||
asm volatile("1: fwait\n"
|
asm volatile("1: fwait\n"
|
||||||
"2:\n"
|
"2:\n"
|
||||||
" .section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,2b));
|
||||||
" .align 8\n"
|
|
||||||
" .quad 1b,2b\n"
|
|
||||||
" .previous\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
|
static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
|
||||||
|
@ -57,10 +55,7 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
|
||||||
"3: movl $-1,%[err]\n"
|
"3: movl $-1,%[err]\n"
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 8\n"
|
|
||||||
" .quad 1b,3b\n"
|
|
||||||
".previous"
|
|
||||||
: [err] "=r" (err)
|
: [err] "=r" (err)
|
||||||
#if 0 /* See comment in __save_init_fpu() below. */
|
#if 0 /* See comment in __save_init_fpu() below. */
|
||||||
: [fx] "r" (fx), "m" (*fx), "0" (0));
|
: [fx] "r" (fx), "m" (*fx), "0" (0));
|
||||||
|
@ -99,10 +94,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
|
||||||
"3: movl $-1,%[err]\n"
|
"3: movl $-1,%[err]\n"
|
||||||
" jmp 2b\n"
|
" jmp 2b\n"
|
||||||
".previous\n"
|
".previous\n"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(1b,3b)
|
||||||
" .align 8\n"
|
|
||||||
" .quad 1b,3b\n"
|
|
||||||
".previous"
|
|
||||||
: [err] "=r" (err), "=m" (*fx)
|
: [err] "=r" (err), "=m" (*fx)
|
||||||
#if 0 /* See comment in __fxsave_clear() below. */
|
#if 0 /* See comment in __fxsave_clear() below. */
|
||||||
: [fx] "r" (fx), "0" (0));
|
: [fx] "r" (fx), "0" (0));
|
||||||
|
|
|
@ -275,29 +275,6 @@ static inline void slow_down_io(void) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_X86_NUMAQ
|
|
||||||
extern void *xquad_portio; /* Where the IO area was mapped */
|
|
||||||
#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
|
|
||||||
#define __BUILDIO(bwl,bw,type) \
|
|
||||||
static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
|
|
||||||
if (xquad_portio) \
|
|
||||||
write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
|
|
||||||
else \
|
|
||||||
out##bwl##_local(value, port); \
|
|
||||||
} \
|
|
||||||
static inline void out##bwl(unsigned type value, int port) { \
|
|
||||||
out##bwl##_quad(value, port, 0); \
|
|
||||||
} \
|
|
||||||
static inline unsigned type in##bwl##_quad(int port, int quad) { \
|
|
||||||
if (xquad_portio) \
|
|
||||||
return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
|
|
||||||
else \
|
|
||||||
return in##bwl##_local(port); \
|
|
||||||
} \
|
|
||||||
static inline unsigned type in##bwl(int port) { \
|
|
||||||
return in##bwl##_quad(port, 0); \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define __BUILDIO(bwl,bw,type) \
|
#define __BUILDIO(bwl,bw,type) \
|
||||||
static inline void out##bwl(unsigned type value, int port) { \
|
static inline void out##bwl(unsigned type value, int port) { \
|
||||||
out##bwl##_local(value, port); \
|
out##bwl##_local(value, port); \
|
||||||
|
@ -305,8 +282,6 @@ static inline void out##bwl(unsigned type value, int port) { \
|
||||||
static inline unsigned type in##bwl(int port) { \
|
static inline unsigned type in##bwl(int port) { \
|
||||||
return in##bwl##_local(port); \
|
return in##bwl##_local(port); \
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define BUILDIO(bwl,bw,type) \
|
#define BUILDIO(bwl,bw,type) \
|
||||||
static inline void out##bwl##_local(unsigned type value, int port) { \
|
static inline void out##bwl##_local(unsigned type value, int port) { \
|
||||||
|
|
|
@ -109,6 +109,8 @@ static inline int mpc_apic_id(struct mpc_config_processor *m,
|
||||||
return logical_apicid;
|
return logical_apicid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void *xquad_portio;
|
||||||
|
|
||||||
static inline void setup_portio_remap(void)
|
static inline void setup_portio_remap(void)
|
||||||
{
|
{
|
||||||
int num_quads = num_online_nodes();
|
int num_quads = num_online_nodes();
|
||||||
|
|
|
@ -57,10 +57,7 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
|
||||||
".section .fixup,\"ax\"\n\t"
|
".section .fixup,\"ax\"\n\t"
|
||||||
"3: mov %3,%0 ; jmp 1b\n\t"
|
"3: mov %3,%0 ; jmp 1b\n\t"
|
||||||
".previous\n\t"
|
".previous\n\t"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(2b,3b)
|
||||||
_ASM_ALIGN "\n\t"
|
|
||||||
_ASM_PTR " 2b,3b\n\t"
|
|
||||||
".previous"
|
|
||||||
: "=r" (*err), EAX_EDX_RET(val, low, high)
|
: "=r" (*err), EAX_EDX_RET(val, low, high)
|
||||||
: "c" (msr), "i" (-EFAULT));
|
: "c" (msr), "i" (-EFAULT));
|
||||||
return EAX_EDX_VAL(val, low, high);
|
return EAX_EDX_VAL(val, low, high);
|
||||||
|
@ -81,10 +78,7 @@ static inline int native_write_msr_safe(unsigned int msr,
|
||||||
".section .fixup,\"ax\"\n\t"
|
".section .fixup,\"ax\"\n\t"
|
||||||
"3: mov %4,%0 ; jmp 1b\n\t"
|
"3: mov %4,%0 ; jmp 1b\n\t"
|
||||||
".previous\n\t"
|
".previous\n\t"
|
||||||
".section __ex_table,\"a\"\n"
|
_ASM_EXTABLE(2b,3b)
|
||||||
_ASM_ALIGN "\n\t"
|
|
||||||
_ASM_PTR " 2b,3b\n\t"
|
|
||||||
".previous"
|
|
||||||
: "=a" (err)
|
: "=a" (err)
|
||||||
: "c" (msr), "0" (low), "d" (high),
|
: "c" (msr), "0" (low), "d" (high),
|
||||||
"i" (-EFAULT));
|
"i" (-EFAULT));
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
|
#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
|
||||||
#define PTE_MASK (_AT(long, PHYSICAL_PAGE_MASK))
|
#define PTE_MASK (_AT(long, PHYSICAL_PAGE_MASK))
|
||||||
|
|
||||||
#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)
|
#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT)
|
||||||
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
|
#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
|
||||||
|
|
||||||
#define HPAGE_SHIFT PMD_SHIFT
|
#define HPAGE_SHIFT PMD_SHIFT
|
||||||
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
|
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
#define MCE_STACK 5
|
#define MCE_STACK 5
|
||||||
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
|
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
|
||||||
|
|
||||||
|
#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
|
||||||
|
#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
|
||||||
|
|
||||||
#define __PAGE_OFFSET _AC(0xffff810000000000, UL)
|
#define __PAGE_OFFSET _AC(0xffff810000000000, UL)
|
||||||
|
|
||||||
#define __PHYSICAL_START CONFIG_PHYSICAL_START
|
#define __PHYSICAL_START CONFIG_PHYSICAL_START
|
||||||
|
|
|
@ -80,8 +80,10 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
|
||||||
set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
|
set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pentium-II erratum A13: in PAE mode we explicitly have to flush
|
* According to Intel App note "TLBs, Paging-Structure Caches,
|
||||||
* the TLB via cr3 if the top-level pgd is changed...
|
* and Their Invalidation", April 2007, document 317080-001,
|
||||||
|
* section 8.1: in PAE mode we explicitly have to flush the
|
||||||
|
* TLB via cr3 if the top-level pgd is changed...
|
||||||
*/
|
*/
|
||||||
if (mm == current->active_mm)
|
if (mm == current->active_mm)
|
||||||
write_cr3(read_cr3());
|
write_cr3(read_cr3());
|
||||||
|
|
|
@ -93,26 +93,22 @@ static inline void native_pmd_clear(pmd_t *pmd)
|
||||||
|
|
||||||
static inline void pud_clear(pud_t *pudp)
|
static inline void pud_clear(pud_t *pudp)
|
||||||
{
|
{
|
||||||
|
unsigned long pgd;
|
||||||
|
|
||||||
set_pud(pudp, __pud(0));
|
set_pud(pudp, __pud(0));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In principle we need to do a cr3 reload here to make sure
|
* According to Intel App note "TLBs, Paging-Structure Caches,
|
||||||
* the processor recognizes the changed pgd. In practice, all
|
* and Their Invalidation", April 2007, document 317080-001,
|
||||||
* the places where pud_clear() gets called are followed by
|
* section 8.1: in PAE mode we explicitly have to flush the
|
||||||
* full tlb flushes anyway, so we can defer the cost here.
|
* TLB via cr3 if the top-level pgd is changed...
|
||||||
*
|
*
|
||||||
* Specifically:
|
* Make sure the pud entry we're updating is within the
|
||||||
*
|
* current pgd to avoid unnecessary TLB flushes.
|
||||||
* mm/memory.c:free_pmd_range() - immediately after the
|
|
||||||
* pud_clear() it does a pmd_free_tlb(). We change the
|
|
||||||
* mmu_gather structure to do a full tlb flush (which has the
|
|
||||||
* effect of reloading cr3) when the pagetable free is
|
|
||||||
* complete.
|
|
||||||
*
|
|
||||||
* arch/x86/mm/hugetlbpage.c:huge_pmd_unshare() - the call to
|
|
||||||
* this is followed by a flush_tlb_range, which on x86 does a
|
|
||||||
* full tlb flush.
|
|
||||||
*/
|
*/
|
||||||
|
pgd = read_cr3();
|
||||||
|
if (__pa(pudp) >= pgd && __pa(pudp) < (pgd + sizeof(pgd_t)*PTRS_PER_PGD))
|
||||||
|
write_cr3(pgd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define pud_page(pud) \
|
#define pud_page(pud) \
|
||||||
|
|
|
@ -13,10 +13,12 @@
|
||||||
#define _PAGE_BIT_DIRTY 6
|
#define _PAGE_BIT_DIRTY 6
|
||||||
#define _PAGE_BIT_FILE 6
|
#define _PAGE_BIT_FILE 6
|
||||||
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
|
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
|
||||||
|
#define _PAGE_BIT_PAT 7 /* on 4KB pages */
|
||||||
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
|
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
|
||||||
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
|
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
|
||||||
#define _PAGE_BIT_UNUSED2 10
|
#define _PAGE_BIT_UNUSED2 10
|
||||||
#define _PAGE_BIT_UNUSED3 11
|
#define _PAGE_BIT_UNUSED3 11
|
||||||
|
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
|
||||||
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
|
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,6 +38,8 @@
|
||||||
#define _PAGE_UNUSED1 (_AC(1, L)<<_PAGE_BIT_UNUSED1)
|
#define _PAGE_UNUSED1 (_AC(1, L)<<_PAGE_BIT_UNUSED1)
|
||||||
#define _PAGE_UNUSED2 (_AC(1, L)<<_PAGE_BIT_UNUSED2)
|
#define _PAGE_UNUSED2 (_AC(1, L)<<_PAGE_BIT_UNUSED2)
|
||||||
#define _PAGE_UNUSED3 (_AC(1, L)<<_PAGE_BIT_UNUSED3)
|
#define _PAGE_UNUSED3 (_AC(1, L)<<_PAGE_BIT_UNUSED3)
|
||||||
|
#define _PAGE_PAT (_AC(1, L)<<_PAGE_BIT_PAT)
|
||||||
|
#define _PAGE_PAT_LARGE (_AC(1, L)<<_PAGE_BIT_PAT_LARGE)
|
||||||
|
|
||||||
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
|
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
|
||||||
#define _PAGE_NX (_AC(1, ULL) << _PAGE_BIT_NX)
|
#define _PAGE_NX (_AC(1, ULL) << _PAGE_BIT_NX)
|
||||||
|
|
|
@ -148,6 +148,8 @@ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
|
||||||
*/
|
*/
|
||||||
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
||||||
|
|
||||||
|
static inline int pud_large(pud_t pud) { return 0; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
|
* the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,7 +21,6 @@ extern pgd_t init_level4_pgt[];
|
||||||
#define swapper_pg_dir init_level4_pgt
|
#define swapper_pg_dir init_level4_pgt
|
||||||
|
|
||||||
extern void paging_init(void);
|
extern void paging_init(void);
|
||||||
extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
|
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
|
@ -199,6 +198,12 @@ static inline unsigned long pmd_bad(pmd_t pmd)
|
||||||
#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
|
#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
|
||||||
#define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
|
#define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
|
||||||
|
|
||||||
|
static inline int pud_large(pud_t pte)
|
||||||
|
{
|
||||||
|
return (pud_val(pte) & (_PAGE_PSE|_PAGE_PRESENT)) ==
|
||||||
|
(_PAGE_PSE|_PAGE_PRESENT);
|
||||||
|
}
|
||||||
|
|
||||||
/* PMD - Level 2 access */
|
/* PMD - Level 2 access */
|
||||||
#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
|
#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
|
||||||
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
|
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
|
||||||
|
|
|
@ -213,14 +213,14 @@ static __always_inline void * __constant_c_and_count_memset(void * s, unsigned l
|
||||||
case 0:
|
case 0:
|
||||||
return s;
|
return s;
|
||||||
case 1:
|
case 1:
|
||||||
*(unsigned char *)s = pattern;
|
*(unsigned char *)s = pattern & 0xff;
|
||||||
return s;
|
return s;
|
||||||
case 2:
|
case 2:
|
||||||
*(unsigned short *)s = pattern;
|
*(unsigned short *)s = pattern & 0xffff;
|
||||||
return s;
|
return s;
|
||||||
case 3:
|
case 3:
|
||||||
*(unsigned short *)s = pattern;
|
*(unsigned short *)s = pattern & 0xffff;
|
||||||
*(2+(unsigned char *)s) = pattern;
|
*(2+(unsigned char *)s) = pattern & 0xff;
|
||||||
return s;
|
return s;
|
||||||
case 4:
|
case 4:
|
||||||
*(unsigned long *)s = pattern;
|
*(unsigned long *)s = pattern;
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
|
||||||
struct task_struct; /* one of the stranger aspects of C forward declarations */
|
struct task_struct; /* one of the stranger aspects of C forward declarations */
|
||||||
extern struct task_struct *FASTCALL(__switch_to(struct task_struct *prev,
|
struct task_struct *__switch_to(struct task_struct *prev,
|
||||||
struct task_struct *next));
|
struct task_struct *next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Saving eflags is important. It switches not only IOPL between tasks,
|
* Saving eflags is important. It switches not only IOPL between tasks,
|
||||||
|
@ -130,10 +130,7 @@ extern void load_gs_index(unsigned);
|
||||||
"movl %k1, %%" #seg "\n\t" \
|
"movl %k1, %%" #seg "\n\t" \
|
||||||
"jmp 2b\n" \
|
"jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n\t" \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
_ASM_ALIGN "\n\t" \
|
|
||||||
_ASM_PTR " 1b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: :"r" (value), "r" (0))
|
: :"r" (value), "r" (0))
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,12 +211,10 @@ static inline unsigned long native_read_cr4_safe(void)
|
||||||
/* This could fault if %cr4 does not exist. In x86_64, a cr4 always
|
/* This could fault if %cr4 does not exist. In x86_64, a cr4 always
|
||||||
* exists, so it will never fail. */
|
* exists, so it will never fail. */
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
asm volatile("1: mov %%cr4, %0 \n"
|
asm volatile("1: mov %%cr4, %0\n"
|
||||||
"2: \n"
|
"2:\n"
|
||||||
".section __ex_table,\"a\" \n"
|
_ASM_EXTABLE(1b,2b)
|
||||||
".long 1b,2b \n"
|
: "=r" (val), "=m" (__force_order) : "0" (0));
|
||||||
".previous \n"
|
|
||||||
: "=r" (val), "=m" (__force_order) : "0" (0));
|
|
||||||
#else
|
#else
|
||||||
val = native_read_cr4();
|
val = native_read_cr4();
|
||||||
#endif
|
#endif
|
||||||
|
@ -276,9 +271,9 @@ static inline void native_wbinvd(void)
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
static inline void clflush(void *__p)
|
static inline void clflush(volatile void *__p)
|
||||||
{
|
{
|
||||||
asm volatile("clflush %0" : "+m" (*(char __force *)__p));
|
asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define nop() __asm__ __volatile__ ("nop")
|
#define nop() __asm__ __volatile__ ("nop")
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
|
|
||||||
#define VERIFY_READ 0
|
#define VERIFY_READ 0
|
||||||
|
@ -287,11 +288,8 @@ extern void __put_user_8(void);
|
||||||
"4: movl %3,%0\n" \
|
"4: movl %3,%0\n" \
|
||||||
" jmp 3b\n" \
|
" jmp 3b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(1b,4b) \
|
||||||
" .align 4\n" \
|
_ASM_EXTABLE(2b,4b) \
|
||||||
" .long 1b,4b\n" \
|
|
||||||
" .long 2b,4b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(err) \
|
: "=r"(err) \
|
||||||
: "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
|
: "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
|
||||||
|
|
||||||
|
@ -338,10 +336,7 @@ struct __large_struct { unsigned long buf[100]; };
|
||||||
"3: movl %3,%0\n" \
|
"3: movl %3,%0\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
" .align 4\n" \
|
|
||||||
" .long 1b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(err) \
|
: "=r"(err) \
|
||||||
: ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
|
: ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
|
||||||
|
|
||||||
|
@ -378,10 +373,7 @@ do { \
|
||||||
" xor"itype" %"rtype"1,%"rtype"1\n" \
|
" xor"itype" %"rtype"1,%"rtype"1\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
" .align 4\n" \
|
|
||||||
" .long 1b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(err), ltype (x) \
|
: "=r"(err), ltype (x) \
|
||||||
: "m"(__m(addr)), "i"(errret), "0"(err))
|
: "m"(__m(addr)), "i"(errret), "0"(err))
|
||||||
|
|
||||||
|
|
|
@ -181,10 +181,7 @@ struct __large_struct { unsigned long buf[100]; };
|
||||||
"3: mov %3,%0\n" \
|
"3: mov %3,%0\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
" .align 8\n" \
|
|
||||||
" .quad 1b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(err) \
|
: "=r"(err) \
|
||||||
: ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
|
: ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
|
||||||
|
|
||||||
|
@ -226,10 +223,7 @@ do { \
|
||||||
" xor"itype" %"rtype"1,%"rtype"1\n" \
|
" xor"itype" %"rtype"1,%"rtype"1\n" \
|
||||||
" jmp 2b\n" \
|
" jmp 2b\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __ex_table,\"a\"\n" \
|
_ASM_EXTABLE(1b,3b) \
|
||||||
" .align 8\n" \
|
|
||||||
" .quad 1b,3b\n" \
|
|
||||||
".previous" \
|
|
||||||
: "=r"(err), ltype (x) \
|
: "=r"(err), ltype (x) \
|
||||||
: "m"(__m(addr)), "i"(errno), "0"(err))
|
: "m"(__m(addr)), "i"(errno), "0"(err))
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,7 @@ struct kernel_vm86_struct {
|
||||||
|
|
||||||
void handle_vm86_fault(struct kernel_vm86_regs *, long);
|
void handle_vm86_fault(struct kernel_vm86_regs *, long);
|
||||||
int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
|
int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
|
||||||
|
struct pt_regs *save_v86_state(struct kernel_vm86_regs *);
|
||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
void release_vm86_irqs(struct task_struct *);
|
void release_vm86_irqs(struct task_struct *);
|
||||||
|
|
Loading…
Reference in a new issue