Commit 402e9d54 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86-64 merge

This brings the x86-64 port uptodate for 2.5.70. Just various bugfixes
and a few merges with other people.

Only changes architecture specific files.

- Fix compiling with CONFIG_IA32_EMULATION on
- Readd lost apic power management patch from Pavel (fixes oprofile too)
- Increase max IOAPICs to 16
- Fix compiling with CONFIG_IA32_EMULATION off
- Compile fix for suspend (Pavel Machek)
- Support boxes with APIC disabled
- Remove code to forcibly enable APIC
- Small fix for APIC timer calibration.
- Fix deadlock in SMP reboot
- Some warning fixes
- Save edid info at boot (Bryan O'Sullivan)
- Add better locking to oops printing and support it for page faults.
- Don't printk handled signals.
- Update defconfig
- Add copy_in_user
parent 7038424c
...@@ -22,6 +22,9 @@ CONFIG_SYSVIPC=y ...@@ -22,6 +22,9 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y CONFIG_SYSCTL=y
CONFIG_LOG_BUF_SHIFT=16 CONFIG_LOG_BUF_SHIFT=16
# CONFIG_EMBEDDED is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# #
# Loadable module support # Loadable module support
...@@ -546,6 +549,7 @@ CONFIG_ISO9660_FS=y ...@@ -546,6 +549,7 @@ CONFIG_ISO9660_FS=y
CONFIG_PROC_FS=y CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y CONFIG_DEVPTS_FS=y
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y CONFIG_TMPFS=y
CONFIG_RAMFS=y CONFIG_RAMFS=y
......
...@@ -13,4 +13,6 @@ $(obj)/vsyscall.so: $(src)/vsyscall.lds $(obj)/vsyscall.o ...@@ -13,4 +13,6 @@ $(obj)/vsyscall.so: $(src)/vsyscall.lds $(obj)/vsyscall.o
$(CC) -m32 -nostdlib -shared -s -Wl,-soname=linux-vsyscall.so.1 \ $(CC) -m32 -nostdlib -shared -s -Wl,-soname=linux-vsyscall.so.1 \
-o $@ -Wl,-T,$^ -o $@ -Wl,-T,$^
clean-files += vsyscall.so
AFLAGS_vsyscall.o = -m32 AFLAGS_vsyscall.o = -m32
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* for testing these extensively. * for testing these extensively.
* Maciej W. Rozycki : Various updates and fixes. * Maciej W. Rozycki : Various updates and fixes.
* Mikael Pettersson : Power Management for UP-APIC. * Mikael Pettersson : Power Management for UP-APIC.
* Pavel Machek and
* Mikael Pettersson : PM converted to driver model.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -120,7 +122,7 @@ void __init connect_bsp_APIC(void) ...@@ -120,7 +122,7 @@ void __init connect_bsp_APIC(void)
* PIC mode, enable APIC mode in the IMCR, i.e. * PIC mode, enable APIC mode in the IMCR, i.e.
* connect BSP's local APIC to INT and NMI lines. * connect BSP's local APIC to INT and NMI lines.
*/ */
printk("leaving PIC mode, enabling APIC mode.\n"); printk(KERN_INFO "leaving PIC mode, enabling APIC mode.\n");
outb(0x70, 0x22); outb(0x70, 0x22);
outb(0x01, 0x23); outb(0x01, 0x23);
} }
...@@ -135,7 +137,7 @@ void disconnect_bsp_APIC(void) ...@@ -135,7 +137,7 @@ void disconnect_bsp_APIC(void)
* interrupts, including IPIs, won't work beyond * interrupts, including IPIs, won't work beyond
* this point! The only exception are INIT IPIs. * this point! The only exception are INIT IPIs.
*/ */
printk("disabling APIC mode, entering PIC mode.\n"); printk(KERN_INFO "disabling APIC mode, entering PIC mode.\n");
outb(0x70, 0x22); outb(0x70, 0x22);
outb(0x00, 0x23); outb(0x00, 0x23);
} }
...@@ -438,17 +440,14 @@ void __init setup_local_APIC (void) ...@@ -438,17 +440,14 @@ void __init setup_local_APIC (void)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#include <linux/slab.h> #include <linux/device.h>
#include <linux/pm.h> #include <linux/module.h>
static struct { static struct {
/* 'active' is true if the local APIC was enabled by us and /* 'active' is true if the local APIC was enabled by us and
not the BIOS; this signifies that we are also responsible not the BIOS; this signifies that we are also responsible
for disabling it before entering apm/acpi suspend */ for disabling it before entering apm/acpi suspend */
int active; int active;
/* 'perfctr_pmdev' is here because the current (2.4.1) PM
callback system doesn't handle hierarchical dependencies */
struct pm_dev *perfctr_pmdev;
/* r/w apic fields */ /* r/w apic fields */
unsigned int apic_id; unsigned int apic_id;
unsigned int apic_taskpri; unsigned int apic_taskpri;
...@@ -465,13 +464,16 @@ static struct { ...@@ -465,13 +464,16 @@ static struct {
unsigned int apic_thmr; unsigned int apic_thmr;
} apic_pm_state; } apic_pm_state;
static void apic_pm_suspend(void *data) static int lapic_suspend(struct device *dev, u32 state, u32 level)
{ {
unsigned int l, h; unsigned int l, h;
unsigned long flags; unsigned long flags;
if (apic_pm_state.perfctr_pmdev) if (level != SUSPEND_POWER_DOWN)
pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data); return 0;
if (!apic_pm_state.active)
return 0;
apic_pm_state.apic_id = apic_read(APIC_ID); apic_pm_state.apic_id = apic_read(APIC_ID);
apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
apic_pm_state.apic_ldr = apic_read(APIC_LDR); apic_pm_state.apic_ldr = apic_read(APIC_LDR);
...@@ -492,15 +494,23 @@ static void apic_pm_suspend(void *data) ...@@ -492,15 +494,23 @@ static void apic_pm_suspend(void *data)
l &= ~MSR_IA32_APICBASE_ENABLE; l &= ~MSR_IA32_APICBASE_ENABLE;
wrmsr(MSR_IA32_APICBASE, l, h); wrmsr(MSR_IA32_APICBASE, l, h);
local_irq_restore(flags); local_irq_restore(flags);
return 0;
} }
static void apic_pm_resume(void *data) static int lapic_resume(struct device *dev, u32 level)
{ {
unsigned int l, h; unsigned int l, h;
unsigned long flags; unsigned long flags;
local_save_flags(flags); if (level != RESUME_POWER_ON)
local_irq_disable(); return 0;
if (!apic_pm_state.active)
return 0;
/* XXX: Pavel needs this for S3 resume, but can't explain why */
set_fixmap_nocache(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
local_irq_save(flags);
rdmsr(MSR_IA32_APICBASE, l, h); rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_BASE; l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
...@@ -524,141 +534,69 @@ static void apic_pm_resume(void *data) ...@@ -524,141 +534,69 @@ static void apic_pm_resume(void *data)
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
apic_read(APIC_ESR); apic_read(APIC_ESR);
local_irq_restore(flags); local_irq_restore(flags);
if (apic_pm_state.perfctr_pmdev)
pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data);
}
static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
{
switch (rqst) {
case PM_SUSPEND:
apic_pm_suspend(data);
break;
case PM_RESUME:
apic_pm_resume(data);
break;
}
return 0; return 0;
} }
/* perfctr driver should call this instead of pm_register() */ static struct device_driver lapic_driver = {
struct pm_dev *apic_pm_register(pm_dev_t type, .name = "lapic",
unsigned long id, .bus = &system_bus_type,
pm_callback callback) .resume = lapic_resume,
{ .suspend = lapic_suspend,
struct pm_dev *dev; };
if (!apic_pm_state.active) /* not static, needed by child devices */
return pm_register(type, id, callback); struct sys_device device_lapic = {
if (apic_pm_state.perfctr_pmdev) .name = "lapic",
return NULL; /* we're busy */ .id = 0,
dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); .dev = {
if (dev) { .name = "lapic",
memset(dev, 0, sizeof(*dev)); .driver = &lapic_driver,
dev->type = type; },
dev->id = id; };
dev->callback = callback; EXPORT_SYMBOL(device_lapic);
apic_pm_state.perfctr_pmdev = dev;
} static void __init apic_pm_activate(void)
return dev;
}
/* perfctr driver should call this instead of pm_unregister() */
void apic_pm_unregister(struct pm_dev *dev)
{
if (!apic_pm_state.active) {
pm_unregister(dev);
} else if (dev == apic_pm_state.perfctr_pmdev) {
apic_pm_state.perfctr_pmdev = NULL;
kfree(dev);
}
}
static void __init apic_pm_init1(void)
{ {
/* can't pm_register() at this early stage in the boot process
(causes an immediate reboot), so just set the flag */
apic_pm_state.active = 1; apic_pm_state.active = 1;
} }
static void __init apic_pm_init2(void) static int __init init_lapic_devicefs(void)
{ {
if (apic_pm_state.active) if (!cpu_has_apic)
pm_register(PM_SYS_DEV, 0, apic_pm_callback); return 0;
/* XXX: remove suspend/resume procs if !apic_pm_state.active? */
driver_register(&lapic_driver);
return sys_device_register(&device_lapic);
} }
device_initcall(init_lapic_devicefs);
#else /* CONFIG_PM */ #else /* CONFIG_PM */
static inline void apic_pm_init1(void) { } static inline void apic_pm_activate(void) { }
static inline void apic_pm_init2(void) { }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/* /*
* Detect and enable local APICs on non-SMP boards. * Detect and enable local APICs on non-SMP boards.
* Original code written by Keir Fraser. * Original code written by Keir Fraser.
* On AMD64 we trust the BIOS - if it says no APIC it is likely
* not correctly set up (usually the APIC timer won't work etc.)
*/ */
static int __init detect_init_APIC (void) static int __init detect_init_APIC (void)
{ {
u32 h, l, features;
extern void get_cpu_vendor(struct cpuinfo_x86*);
/* Workaround for us being called before identify_cpu(). */
get_cpu_vendor(&boot_cpu_data);
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
if (boot_cpu_data.x86 > 6)
break;
goto no_apic;
case X86_VENDOR_INTEL:
if (boot_cpu_data.x86 == 6 ||
(boot_cpu_data.x86 == 15 && cpu_has_apic) ||
(boot_cpu_data.x86 == 5 && cpu_has_apic))
break;
goto no_apic;
default:
goto no_apic;
}
if (!cpu_has_apic) { if (!cpu_has_apic) {
/* printk(KERN_INFO "No local APIC present\n");
* Some BIOSes disable the local APIC in the
* APIC_BASE MSR. This can only be done in
* software for Intel P6 and AMD K7 (Model > 1).
*/
rdmsr(MSR_IA32_APICBASE, l, h);
if (!(l & MSR_IA32_APICBASE_ENABLE)) {
printk("Local APIC disabled by BIOS -- reenabling.\n");
l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
wrmsr(MSR_IA32_APICBASE, l, h);
}
}
/*
* The APIC feature bit should now be enabled
* in `cpuid'
*/
features = cpuid_edx(1);
if (!(features & (1 << X86_FEATURE_APIC))) {
printk("Could not enable APIC!\n");
return -1; return -1;
} }
set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
boot_cpu_id = 0; boot_cpu_id = 0;
if (nmi_watchdog != NMI_NONE) if (nmi_watchdog != NMI_NONE)
nmi_watchdog = NMI_LOCAL_APIC; nmi_watchdog = NMI_LOCAL_APIC;
apic_pm_init1(); apic_pm_activate();
printk("Found and enabled local APIC!\n");
return 0; return 0;
no_apic:
printk("No local APIC present or hardware disabled\n");
return -1;
} }
void __init init_apic_mappings(void) void __init init_apic_mappings(void)
...@@ -745,13 +683,11 @@ static void setup_APIC_timer(unsigned int clocks) ...@@ -745,13 +683,11 @@ static void setup_APIC_timer(unsigned int clocks)
local_irq_save(flags); local_irq_save(flags);
#if 0
/* For some reasons this doesn't work on Simics, so fake it for now */ /* For some reasons this doesn't work on Simics, so fake it for now */
if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) { if (!strstr(boot_cpu_data.x86_model_id, "Screwdriver")) {
__setup_APIC_LVTT(clocks); __setup_APIC_LVTT(clocks);
return; return;
} }
#endif
/* wait for irq slice */ /* wait for irq slice */
{ {
...@@ -808,7 +744,7 @@ int __init calibrate_APIC_clock(void) ...@@ -808,7 +744,7 @@ int __init calibrate_APIC_clock(void)
result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start); result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start);
printk("Detected %d.%03d MHz APIC timer.\n", printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
result / 1000 / 1000, result / 1000 % 1000); result / 1000 / 1000, result / 1000 % 1000);
return result * APIC_DIVISOR / HZ; return result * APIC_DIVISOR / HZ;
...@@ -819,11 +755,11 @@ static unsigned int calibration_result; ...@@ -819,11 +755,11 @@ static unsigned int calibration_result;
void __init setup_boot_APIC_clock (void) void __init setup_boot_APIC_clock (void)
{ {
if (disable_apic_timer) { if (disable_apic_timer) {
printk("Disabling APIC timer\n"); printk(KERN_INFO "Disabling APIC timer\n");
return; return;
} }
printk("Using local APIC timer interrupts.\n"); printk(KERN_INFO "Using local APIC timer interrupts.\n");
using_apic_timer = 1; using_apic_timer = 1;
local_irq_disable(); local_irq_disable();
...@@ -1051,18 +987,9 @@ int __init APIC_init_uniprocessor (void) ...@@ -1051,18 +987,9 @@ int __init APIC_init_uniprocessor (void)
printk(KERN_INFO "Apic disabled\n"); printk(KERN_INFO "Apic disabled\n");
return -1; return -1;
} }
if (!smp_found_config && !cpu_has_apic) { if (!cpu_has_apic) {
disable_apic = 1;
return -1;
}
/*
* Complain if the BIOS pretends there is one.
*/
if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_id);
disable_apic = 1; disable_apic = 1;
printk(KERN_INFO "Apic disabled by BIOS\n");
return -1; return -1;
} }
...@@ -1073,8 +1000,6 @@ int __init APIC_init_uniprocessor (void) ...@@ -1073,8 +1000,6 @@ int __init APIC_init_uniprocessor (void)
phys_cpu_present_map = 1; phys_cpu_present_map = 1;
apic_write_around(APIC_ID, boot_cpu_id); apic_write_around(APIC_ID, boot_cpu_id);
apic_pm_init2();
setup_local_APIC(); setup_local_APIC();
if (nmi_watchdog == NMI_LOCAL_APIC) if (nmi_watchdog == NMI_LOCAL_APIC)
......
...@@ -44,6 +44,7 @@ int main(void) ...@@ -44,6 +44,7 @@ int main(void)
ENTRY(irqstackptr); ENTRY(irqstackptr);
BLANK(); BLANK();
#undef ENTRY #undef ENTRY
#ifdef CONFIG_IA32_EMULATION
#define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry)) #define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry))
ENTRY(eax); ENTRY(eax);
ENTRY(ebx); ENTRY(ebx);
...@@ -59,6 +60,7 @@ int main(void) ...@@ -59,6 +60,7 @@ int main(void)
DEFINE(IA32_RT_SIGFRAME_sigcontext, DEFINE(IA32_RT_SIGFRAME_sigcontext,
offsetof (struct rt_sigframe32, uc.uc_mcontext)); offsetof (struct rt_sigframe32, uc.uc_mcontext));
BLANK(); BLANK();
#endif
return 0; return 0;
} }
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* Fixes: * Fixes:
* Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog.
* Mikael Pettersson : Power Management for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog.
* Pavel Machek and
* Mikael Pettersson : PM converted to driver model. Disable/enable API.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -19,6 +21,7 @@ ...@@ -19,6 +21,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/module.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
...@@ -113,14 +116,18 @@ static int __init setup_nmi_watchdog(char *str) ...@@ -113,14 +116,18 @@ static int __init setup_nmi_watchdog(char *str)
__setup("nmi_watchdog=", setup_nmi_watchdog); __setup("nmi_watchdog=", setup_nmi_watchdog);
#ifdef CONFIG_PM /* nmi_active:
* +1: the lapic NMI watchdog is active, but can be disabled
#include <linux/pm.h> * 0: the lapic NMI watchdog has not been set up, and cannot
* be enabled
struct pm_dev *nmi_pmdev; * -1: the lapic NMI watchdog is disabled, but can be enabled
*/
static int nmi_active;
static void disable_apic_nmi_watchdog(void) void disable_lapic_nmi_watchdog(void)
{ {
if (nmi_active <= 0)
return;
switch (boot_cpu_data.x86_vendor) { switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
wrmsr(MSR_K7_EVNTSEL0, 0, 0); wrmsr(MSR_K7_EVNTSEL0, 0, 0);
...@@ -129,46 +136,66 @@ static void disable_apic_nmi_watchdog(void) ...@@ -129,46 +136,66 @@ static void disable_apic_nmi_watchdog(void)
wrmsr(MSR_IA32_EVNTSEL0, 0, 0); wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
break; break;
} }
nmi_active = -1;
/* tell do_nmi() and others that we're not active any more */
nmi_watchdog = 0;
} }
void enable_lapic_nmi_watchdog(void)
static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
{ if (nmi_active < 0) {
switch (rqst) { nmi_watchdog = NMI_LOCAL_APIC;
case PM_SUSPEND:
disable_apic_nmi_watchdog();
break;
case PM_RESUME:
setup_apic_nmi_watchdog(); setup_apic_nmi_watchdog();
break;
} }
return 0; }
}
struct pm_dev * set_nmi_pm_callback(pm_callback callback)
{
apic_pm_unregister(nmi_pmdev);
return apic_pm_register(PM_SYS_DEV, 0, callback);
}
void unset_nmi_pm_callback(struct pm_dev * dev)
{
apic_pm_unregister(dev);
nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
}
static void nmi_pm_init(void) #ifdef CONFIG_PM
{
if (!nmi_pmdev)
nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
}
#define __pminit /*empty*/ #include <linux/device.h>
#else /* CONFIG_PM */ static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level)
{
if (level != SUSPEND_POWER_DOWN)
return 0;
disable_lapic_nmi_watchdog();
return 0;
}
static inline void nmi_pm_init(void) { } static int lapic_nmi_resume(struct device *dev, u32 level)
{
if (level != RESUME_POWER_ON)
return 0;
#if 0
enable_lapic_nmi_watchdog();
#endif
return 0;
}
#define __pminit __init static struct device_driver lapic_nmi_driver = {
.name = "lapic_nmi",
.bus = &system_bus_type,
.resume = lapic_nmi_resume,
.suspend = lapic_nmi_suspend,
};
static struct sys_device device_lapic_nmi = {
.name = "lapic_nmi",
.id = 0,
.dev = {
.name = "lapic_nmi",
.driver = &lapic_nmi_driver,
.parent = &device_lapic.dev,
},
};
static int __init init_lapic_nmi_devicefs(void)
{
if (nmi_active == 0)
return 0;
driver_register(&lapic_nmi_driver);
return sys_device_register(&device_lapic_nmi);
}
/* must come after the local APIC's device_initcall() */
late_initcall(init_lapic_nmi_devicefs);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -217,7 +244,7 @@ void setup_apic_nmi_watchdog (void) ...@@ -217,7 +244,7 @@ void setup_apic_nmi_watchdog (void)
default: default:
return; return;
} }
nmi_pm_init(); nmi_active = 1;
} }
static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
...@@ -261,7 +288,6 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) ...@@ -261,7 +288,6 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
int sum, cpu = safe_smp_processor_id(); int sum, cpu = safe_smp_processor_id();
sum = read_pda(apic_timer_irqs); sum = read_pda(apic_timer_irqs);
if (last_irq_sums[cpu] == sum) { if (last_irq_sums[cpu] == sum) {
/* /*
* Ayiee, looks like this CPU is stuck ... * Ayiee, looks like this CPU is stuck ...
...@@ -307,16 +333,11 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code) ...@@ -307,16 +333,11 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
int cpu = safe_smp_processor_id(); int cpu = safe_smp_processor_id();
init_tss[cpu].ist[NMI_STACK] -= 2048; /* this shouldn't be needed. */ init_tss[cpu].ist[NMI_STACK] -= 2048; /* this shouldn't be needed. */
nmi_enter(); nmi_enter();
add_pda(__nmi_count,1); add_pda(__nmi_count,1);
if (!nmi_callback(regs, cpu)) if (!nmi_callback(regs, cpu))
default_do_nmi(regs); default_do_nmi(regs);
nmi_exit(); nmi_exit();
init_tss[cpu].ist[NMI_STACK] += 2048; init_tss[cpu].ist[NMI_STACK] += 2048;
} }
...@@ -329,3 +350,7 @@ void unset_nmi_callback(void) ...@@ -329,3 +350,7 @@ void unset_nmi_callback(void)
{ {
nmi_callback = dummy_nmi_callback; nmi_callback = dummy_nmi_callback;
} }
EXPORT_SYMBOL(nmi_watchdog);
EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/apic.h>
/* /*
* Power off function, if any * Power off function, if any
...@@ -93,21 +94,24 @@ static void reboot_warm(void) ...@@ -93,21 +94,24 @@ static void reboot_warm(void)
static void smp_halt(void) static void smp_halt(void)
{ {
int cpuid = safe_smp_processor_id(); int cpuid = safe_smp_processor_id();
/* Only run this on the boot processor */
if (cpuid != boot_cpu_id) {
static int first_entry = 1; static int first_entry = 1;
if (first_entry) { if (first_entry) {
first_entry = 0; first_entry = 0;
smp_call_function((void *)machine_restart, NULL, 1, 0); smp_call_function((void *)machine_restart, NULL, 1, 0);
} else {
/* AP reentering. just halt */
for(;;)
asm volatile("hlt");
} }
smp_stop_cpu();
/* AP calling this. Just halt */
if (cpuid != boot_cpu_id) {
for (;;)
asm("hlt");
} }
smp_send_stop();
/* Wait for all other CPUs to have run smp_stop_cpu */
while (cpu_online_map)
rep_nop();
} }
#endif #endif
...@@ -128,8 +132,16 @@ void machine_restart(char * __unused) ...@@ -128,8 +132,16 @@ void machine_restart(char * __unused)
smp_halt(); smp_halt();
#endif #endif
local_irq_disable();
#ifndef CONFIG_SMP
disable_local_APIC();
#endif
disable_IO_APIC(); disable_IO_APIC();
local_irq_enable();
/* Tell the BIOS if we want cold or warm reboot */ /* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode; *((unsigned short *)__va(0x472)) = reboot_mode;
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <video/edid.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
...@@ -53,8 +54,6 @@ ...@@ -53,8 +54,6 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/proto.h> #include <asm/proto.h>
#define Dprintk(x...) printk(x)
/* /*
* Machine setup.. * Machine setup..
*/ */
...@@ -81,6 +80,7 @@ struct sys_desc_table_struct { ...@@ -81,6 +80,7 @@ struct sys_desc_table_struct {
unsigned char table[0]; unsigned char table[0];
}; };
struct edid_info edid_info;
struct e820map e820; struct e820map e820;
unsigned char aux_device_present; unsigned char aux_device_present;
...@@ -243,11 +243,10 @@ static void __init contig_initmem_init(void) ...@@ -243,11 +243,10 @@ static void __init contig_initmem_init(void)
void __init setup_arch(char **cmdline_p) void __init setup_arch(char **cmdline_p)
{ {
Dprintk("setup_arch\n");
ROOT_DEV = ORIG_ROOT_DEV; ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO; drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO; screen_info = SCREEN_INFO;
edid_info = EDID_INFO;
aux_device_present = AUX_DEVICE_INFO; aux_device_present = AUX_DEVICE_INFO;
saved_video_mode = SAVED_VIDEO_MODE; saved_video_mode = SAVED_VIDEO_MODE;
......
...@@ -425,7 +425,7 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ...@@ -425,7 +425,7 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
return 0; return 0;
} }
static void stop_this_cpu (void * dummy) void smp_stop_cpu(void)
{ {
/* /*
* Remove this CPU: * Remove this CPU:
...@@ -433,21 +433,20 @@ static void stop_this_cpu (void * dummy) ...@@ -433,21 +433,20 @@ static void stop_this_cpu (void * dummy)
clear_bit(smp_processor_id(), &cpu_online_map); clear_bit(smp_processor_id(), &cpu_online_map);
local_irq_disable(); local_irq_disable();
disable_local_APIC(); disable_local_APIC();
for(;;) __asm__("hlt"); local_irq_enable();
for (;;);
} }
/* static void smp_really_stop_cpu(void *dummy)
* this function calls the 'stop' function on all other CPUs in the system. {
*/ smp_stop_cpu();
for (;;)
asm("hlt");
}
void smp_send_stop(void) void smp_send_stop(void)
{ {
smp_call_function(stop_this_cpu, NULL, 1, 0); smp_call_function(smp_really_stop_cpu, NULL, 1, 0);
smp_stop_cpu();
local_irq_disable();
disable_local_APIC();
local_irq_enable();
} }
/* /*
......
...@@ -130,7 +130,7 @@ void fix_processor_context(void) ...@@ -130,7 +130,7 @@ void fix_processor_context(void)
/* /*
* Now maybe reload the debug registers * Now maybe reload the debug registers
*/ */
if (current->thread.debugreg[7]){ if (current->thread.debugreg7){
loaddebug(&current->thread, 0); loaddebug(&current->thread, 0);
loaddebug(&current->thread, 1); loaddebug(&current->thread, 1);
loaddebug(&current->thread, 2); loaddebug(&current->thread, 2);
......
...@@ -70,11 +70,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi ...@@ -70,11 +70,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
struct vm_area_struct *vma; struct vm_area_struct *vma;
unsigned long end = TASK_SIZE; unsigned long end = TASK_SIZE;
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32)) { if (test_thread_flag(TIF_IA32)) {
if (!addr) if (!addr)
addr = TASK_UNMAPPED_32; addr = TASK_UNMAPPED_32;
end = IA32_PAGE_OFFSET; end = IA32_PAGE_OFFSET;
} else if (flags & MAP_32BIT) { } else
#endif
if (flags & MAP_32BIT) {
/* This is usually used needed to map code in small model, so it needs to /* This is usually used needed to map code in small model, so it needs to
be in the first 31bit. Limit it to that. be in the first 31bit. Limit it to that.
This means we need to move the unmapped base down for this case. This can This means we need to move the unmapped base down for this case. This can
......
...@@ -318,19 +318,12 @@ void out_of_line_bug(void) ...@@ -318,19 +318,12 @@ void out_of_line_bug(void)
BUG(); BUG();
} }
spinlock_t die_lock = SPIN_LOCK_UNLOCKED; static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
int die_owner = -1; static int die_owner = -1;
void die(const char * str, struct pt_regs * regs, long err) void oops_begin(void)
{ {
static int die_counter; int cpu = safe_smp_processor_id();
int cpu;
console_verbose();
bust_spinlocks(1);
handle_BUG(regs);
printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff, ++die_counter);
notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
cpu = safe_smp_processor_id();
/* racy, but better than risking deadlock. */ /* racy, but better than risking deadlock. */
local_irq_disable(); local_irq_disable();
if (!spin_trylock(&die_lock)) { if (!spin_trylock(&die_lock)) {
...@@ -340,12 +333,29 @@ void die(const char * str, struct pt_regs * regs, long err) ...@@ -340,12 +333,29 @@ void die(const char * str, struct pt_regs * regs, long err)
spin_lock(&die_lock); spin_lock(&die_lock);
} }
die_owner = cpu; die_owner = cpu;
console_verbose();
bust_spinlocks(1);
}
void __die(const char * str, struct pt_regs * regs, long err)
{
static int die_counter;
handle_BUG(regs);
printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff, ++die_counter);
notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
show_registers(regs); show_registers(regs);
bust_spinlocks(0); bust_spinlocks(0);
die_owner = -1;
spin_unlock_irq(&die_lock); spin_unlock_irq(&die_lock);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
void die(const char * str, struct pt_regs * regs, long err)
{
oops_begin();
__die(str, regs, err);
}
static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{ {
if (!(regs->eflags & VM_MASK) && (regs->cs == __KERNEL_CS)) if (!(regs->eflags & VM_MASK) && (regs->cs == __KERNEL_CS))
...@@ -382,9 +392,13 @@ static void do_trap(int trapnr, int signr, char *str, ...@@ -382,9 +392,13 @@ static void do_trap(int trapnr, int signr, char *str,
if ((regs->cs & 3) != 0) { if ((regs->cs & 3) != 0) {
struct task_struct *tsk = current; struct task_struct *tsk = current;
if (exception_trace && trapnr != 3) if (exception_trace && !(tsk->ptrace & PT_PTRACED) &&
printk("%s[%d] trap %s at rip:%lx rsp:%lx err:%lx\n", (tsk->sighand->action[signr-1].sa.sa_handler == SIG_IGN ||
tsk->comm, tsk->pid, str, regs->rip, regs->rsp, error_code); (tsk->sighand->action[signr-1].sa.sa_handler == SIG_DFL)))
printk(KERN_INFO
"%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid, str,
regs->rip,regs->rsp,error_code);
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_no = trapnr; tsk->thread.trap_no = trapnr;
...@@ -401,12 +415,6 @@ static void do_trap(int trapnr, int signr, char *str, ...@@ -401,12 +415,6 @@ static void do_trap(int trapnr, int signr, char *str,
const struct exception_table_entry *fixup; const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->rip); fixup = search_exception_tables(regs->rip);
if (fixup) { if (fixup) {
extern int exception_trace;
if (exception_trace)
printk(KERN_ERR
"%s: fixed kernel exception at %lx err:%ld\n",
current->comm, regs->rip, error_code);
regs->rip = fixup->fixup; regs->rip = fixup->fixup;
} else } else
die(str, regs, error_code); die(str, regs, error_code);
...@@ -471,9 +479,14 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) ...@@ -471,9 +479,14 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
if ((regs->cs & 3)!=0) { if ((regs->cs & 3)!=0) {
struct task_struct *tsk = current; struct task_struct *tsk = current;
if (exception_trace)
printk("%s[%d] #gp at rip:%lx rsp:%lx err:%lx\n", if (exception_trace && !(tsk->ptrace & PT_PTRACED) &&
tsk->comm, tsk->pid, regs->rip, regs->rsp, error_code); (tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_IGN ||
(tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_DFL)))
printk(KERN_INFO
"%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid,
regs->rip,regs->rsp,error_code);
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_no = 13; tsk->thread.trap_no = 13;
......
...@@ -95,6 +95,7 @@ EXPORT_SYMBOL(__clear_user); ...@@ -95,6 +95,7 @@ EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(copy_user_generic); EXPORT_SYMBOL(copy_user_generic);
EXPORT_SYMBOL(copy_from_user); EXPORT_SYMBOL(copy_from_user);
EXPORT_SYMBOL(copy_to_user); EXPORT_SYMBOL(copy_to_user);
EXPORT_SYMBOL(copy_in_user);
EXPORT_SYMBOL(strnlen_user); EXPORT_SYMBOL(strnlen_user);
EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_alloc_consistent);
...@@ -121,11 +122,6 @@ EXPORT_SYMBOL(synchronize_irq); ...@@ -121,11 +122,6 @@ EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function);
#endif #endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
EXPORT_SYMBOL_GPL(set_nmi_pm_callback);
EXPORT_SYMBOL_GPL(unset_nmi_pm_callback);
#endif
#ifdef CONFIG_VT #ifdef CONFIG_VT
EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(screen_info);
#endif #endif
......
...@@ -141,3 +141,11 @@ long strlen_user(const char *s) ...@@ -141,3 +141,11 @@ long strlen_user(const char *s)
s++; s++;
} }
} }
unsigned long copy_in_user(void *to, const void *from, unsigned len)
{
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
return copy_user_generic(to, from, len);
}
return len;
}
...@@ -32,10 +32,6 @@ ...@@ -32,10 +32,6 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/proto.h> #include <asm/proto.h>
extern void die(const char *,struct pt_regs *,long);
extern spinlock_t console_lock;
void bust_spinlocks(int yes) void bust_spinlocks(int yes)
{ {
int loglevel_save = console_loglevel; int loglevel_save = console_loglevel;
...@@ -238,10 +234,13 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -238,10 +234,13 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if (error_code & 4) { if (error_code & 4) {
if (exception_trace && !(tsk->ptrace & PT_PTRACED) &&
(tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_IGN ||
(tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_DFL)))
printk(KERN_INFO printk(KERN_INFO
"%s[%d] segfault at rip:%lx rsp:%lx adr:%lx err:%lx\n", "%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
tsk->comm, tsk->pid, regs->rip, regs->rsp, address, tsk->comm, tsk->pid, address, regs->rip,
error_code); regs->rsp, error_code);
tsk->thread.cr2 = address; tsk->thread.cr2 = address;
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
...@@ -260,10 +259,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -260,10 +259,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
fixup = search_exception_tables(regs->rip); fixup = search_exception_tables(regs->rip);
if (fixup) { if (fixup) {
regs->rip = fixup->fixup; regs->rip = fixup->fixup;
if (0 && exception_trace)
printk(KERN_ERR
"%s: fixed kernel exception at %lx address %lx err:%ld\n",
current->comm, regs->rip, address, error_code);
return; return;
} }
...@@ -272,7 +267,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -272,7 +267,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
* terminate things with extreme prejudice. * terminate things with extreme prejudice.
*/ */
bust_spinlocks(1); oops_begin();
if (address < PAGE_SIZE) if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
...@@ -282,8 +277,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -282,8 +277,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
printk(" printing rip:\n"); printk(" printing rip:\n");
printk("%016lx\n", regs->rip); printk("%016lx\n", regs->rip);
dump_pagetable(address); dump_pagetable(address);
die("Oops", regs, error_code); __die("Oops", regs, error_code);
bust_spinlocks(0);
/* never reached */
do_exit(SIGKILL); do_exit(SIGKILL);
/* /*
......
...@@ -75,13 +75,16 @@ extern void smp_local_timer_interrupt (struct pt_regs * regs); ...@@ -75,13 +75,16 @@ extern void smp_local_timer_interrupt (struct pt_regs * regs);
extern void setup_boot_APIC_clock (void); extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void); extern void setup_secondary_APIC_clock (void);
extern void setup_apic_nmi_watchdog (void); extern void setup_apic_nmi_watchdog (void);
extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); extern void disable_lapic_nmi_watchdog(void);
extern void enable_lapic_nmi_watchdog(void);
extern inline void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
extern int APIC_init_uniprocessor (void); extern int APIC_init_uniprocessor (void);
extern void disable_APIC_timer(void); extern void disable_APIC_timer(void);
extern void enable_APIC_timer(void); extern void enable_APIC_timer(void);
extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback); #ifdef CONFIG_PM
extern void apic_pm_unregister(struct pm_dev*); extern struct sys_device device_lapic;
#endif
extern int check_nmi_watchdog (void); extern int check_nmi_watchdog (void);
......
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
#define MAX_IO_APICS 8 #define MAX_IO_APICS 16
/* /*
* the local APIC register structure, memory mapped. Not terribly well * the local APIC register structure, memory mapped. Not terribly well
......
...@@ -25,6 +25,7 @@ extern char x86_boot_params[2048]; ...@@ -25,6 +25,7 @@ extern char x86_boot_params[2048];
#define KERNEL_START (*(unsigned int *) (PARAM+0x214)) #define KERNEL_START (*(unsigned int *) (PARAM+0x214))
#define INITRD_START (*(unsigned int *) (PARAM+0x218)) #define INITRD_START (*(unsigned int *) (PARAM+0x218))
#define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c)) #define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c))
#define EDID_INFO (*(struct edid_info *) (PARAM+0x440))
#define COMMAND_LINE saved_command_line #define COMMAND_LINE saved_command_line
#define COMMAND_LINE_SIZE 256 #define COMMAND_LINE_SIZE 256
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
#define cpu_has_tsc 1 #define cpu_has_tsc 1
#define cpu_has_pae ___BUG___ #define cpu_has_pae ___BUG___
#define cpu_has_pge 1 #define cpu_has_pge 1
#define cpu_has_apic 1 #define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
#define cpu_has_mtrr 1 #define cpu_has_mtrr 1
#define cpu_has_mmx 1 #define cpu_has_mmx 1
#define cpu_has_fxsr 1 #define cpu_has_fxsr 1
......
...@@ -51,6 +51,10 @@ extern void acpi_reserve_bootmem(void); ...@@ -51,6 +51,10 @@ extern void acpi_reserve_bootmem(void);
extern void swap_low_mappings(void); extern void swap_low_mappings(void);
extern void oops_begin(void);
extern void die(const char *,struct pt_regs *,long);
extern void __die(const char * str, struct pt_regs * regs, long err);
extern int map_syscall32(struct mm_struct *mm, unsigned long address); extern int map_syscall32(struct mm_struct *mm, unsigned long address);
extern char *syscall32_page; extern char *syscall32_page;
......
...@@ -45,6 +45,8 @@ extern void smp_send_reschedule(int cpu); ...@@ -45,6 +45,8 @@ extern void smp_send_reschedule(int cpu);
extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void smp_invalidate_rcv(void); /* Process an NMI */
extern void (*mtrr_hook) (void); extern void (*mtrr_hook) (void);
extern void zap_low_mappings(void); extern void zap_low_mappings(void);
void smp_stop_cpu(void);
#define SMP_TRAMPOLINE_BASE 0x6000 #define SMP_TRAMPOLINE_BASE 0x6000
......
...@@ -41,7 +41,7 @@ extern unsigned long saved_context_eflags; ...@@ -41,7 +41,7 @@ extern unsigned long saved_context_eflags;
#define loaddebug(thread,register) \ #define loaddebug(thread,register) \
__asm__("movq %0,%%db" #register \ __asm__("movq %0,%%db" #register \
: /* no output */ \ : /* no output */ \
:"r" ((thread)->debugreg[register])) :"r" ((thread)->debugreg##register))
extern void fix_processor_context(void); extern void fix_processor_context(void);
extern void do_magic(int resume); extern void do_magic(int resume);
......
...@@ -237,6 +237,7 @@ extern unsigned long copy_user_generic(void *to, const void *from, unsigned len) ...@@ -237,6 +237,7 @@ extern unsigned long copy_user_generic(void *to, const void *from, unsigned len)
extern unsigned long copy_to_user(void *to, const void *from, unsigned len); extern unsigned long copy_to_user(void *to, const void *from, unsigned len);
extern unsigned long copy_from_user(void *to, const void *from, unsigned len); extern unsigned long copy_from_user(void *to, const void *from, unsigned len);
extern unsigned long copy_in_user(void *to, const void *from, unsigned len);
static inline int __copy_from_user(void *dst, const void *src, unsigned size) static inline int __copy_from_user(void *dst, const void *src, unsigned size)
{ {
...@@ -298,6 +299,47 @@ static inline int __copy_to_user(void *dst, const void *src, unsigned size) ...@@ -298,6 +299,47 @@ static inline int __copy_to_user(void *dst, const void *src, unsigned size)
} }
} }
static inline int __copy_in_user(void *dst, const void *src, unsigned size)
{
if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size);
int ret = 0;
switch (size) {
case 1: {
u8 tmp;
__get_user_asm(tmp,(u8 *)src,ret,"b","b","=q",1);
if (!ret)
__put_user_asm(tmp,(u8 *)dst,ret,"b","b","iq",1);
return ret;
}
case 2: {
u16 tmp;
__get_user_asm(tmp,(u16 *)src,ret,"w","w","=r",2);
if (!ret)
__put_user_asm(tmp,(u16 *)dst,ret,"w","w","ir",2);
return ret;
}
case 4: {
u32 tmp;
__get_user_asm(tmp,(u32 *)src,ret,"l","k","=r",4);
if (!ret)
__put_user_asm(tmp,(u32 *)dst,ret,"l","k","ir",4);
return ret;
}
case 8: {
u64 tmp;
__get_user_asm(tmp,(u64 *)src,ret,"q","","=r",8);
if (!ret)
__put_user_asm(tmp,(u64 *)dst,ret,"q","","ir",8);
return ret;
}
default:
return copy_user_generic(dst,src,size);
}
}
long strncpy_from_user(char *dst, const char *src, long count); long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count); long __strncpy_from_user(char *dst, const char *src, long count);
long strnlen_user(const char *str, long n); long strnlen_user(const char *str, long n);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment