summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/.gitignore1
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/cpu/common.c32
-rw-r--r--arch/i386/kernel/cpu/transmeta.c1
-rw-r--r--arch/i386/kernel/efi.c12
-rw-r--r--arch/i386/kernel/head.S6
-rw-r--r--arch/i386/kernel/i386_ksyms.c2
-rw-r--r--arch/i386/kernel/io_apic.c6
-rw-r--r--arch/i386/kernel/kprobes.c16
-rw-r--r--arch/i386/kernel/mpparse.c12
-rw-r--r--arch/i386/kernel/smpboot.c10
-rw-r--r--arch/i386/kernel/syscall_table.S2
-rw-r--r--arch/i386/kernel/timers/timer_tsc.c5
-rw-r--r--arch/i386/kernel/topology.c97
-rw-r--r--arch/i386/kernel/vsyscall-sysenter.S15
15 files changed, 187 insertions, 32 deletions
diff --git a/arch/i386/kernel/.gitignore b/arch/i386/kernel/.gitignore
new file mode 100644
index 000000000000..40836ad9079c
--- /dev/null
+++ b/arch/i386/kernel/.gitignore
@@ -0,0 +1 @@
+vsyscall.lds
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 60c3f76dfca4..53bb9a79e274 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
- quirks.o i8237.o
+ quirks.o i8237.o topology.o
obj-y += cpu/
obj-y += timers/
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 7eb9213734a3..4ecd4b326ded 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -4,6 +4,7 @@
#include <linux/smp.h>
#include <linux/module.h>
#include <linux/percpu.h>
+#include <linux/bootmem.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/i387.h>
@@ -18,6 +19,9 @@
#include "cpu.h"
+DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
+EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
+
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
@@ -571,8 +575,9 @@ void __devinit cpu_init(void)
int cpu = smp_processor_id();
struct tss_struct * t = &per_cpu(init_tss, cpu);
struct thread_struct *thread = &current->thread;
- struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+ struct desc_struct *gdt;
__u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
+ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
if (cpu_test_and_set(cpu, cpu_initialized)) {
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
@@ -590,6 +595,25 @@ void __devinit cpu_init(void)
}
/*
+ * This is a horrible hack to allocate the GDT. The problem
+ * is that cpu_init() is called really early for the boot CPU
+ * (and hence needs bootmem) but much later for the secondary
+ * CPUs, when bootmem will have gone away
+ */
+ if (NODE_DATA(0)->bdata->node_bootmem_map) {
+ gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
+ /* alloc_bootmem_pages panics on failure, so no check */
+ memset(gdt, 0, PAGE_SIZE);
+ } else {
+ gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
+ if (unlikely(!gdt)) {
+ printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
+ for (;;)
+ local_irq_enable();
+ }
+ }
+
+ /*
* Initialize the per-CPU GDT with the boot GDT,
* and set up the GDT descriptor:
*/
@@ -601,10 +625,10 @@ void __devinit cpu_init(void)
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
(CPU_16BIT_STACK_SIZE - 1);
- cpu_gdt_descr[cpu].size = GDT_SIZE - 1;
- cpu_gdt_descr[cpu].address = (unsigned long)gdt;
+ cpu_gdt_descr->size = GDT_SIZE - 1;
+ cpu_gdt_descr->address = (unsigned long)gdt;
- load_gdt(&cpu_gdt_descr[cpu]);
+ load_gdt(cpu_gdt_descr);
load_idt(&idt_descr);
/*
diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
index bdbeb77f4e22..7214c9b577ab 100644
--- a/arch/i386/kernel/cpu/transmeta.c
+++ b/arch/i386/kernel/cpu/transmeta.c
@@ -1,4 +1,5 @@
#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/init.h>
#include <asm/processor.h>
#include <asm/msr.h>
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index ecad519fd395..e3e42fd62401 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -103,17 +103,19 @@ static void efi_call_phys_prelog(void)
*/
local_flush_tlb();
- cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
- load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]));
+ per_cpu(cpu_gdt_descr, 0).address =
+ __pa(per_cpu(cpu_gdt_descr, 0).address);
+ load_gdt((struct Xgt_desc_struct *)__pa(&per_cpu(cpu_gdt_descr, 0)));
}
static void efi_call_phys_epilog(void)
{
unsigned long cr4;
- cpu_gdt_descr[0].address =
- (unsigned long) __va(cpu_gdt_descr[0].address);
- load_gdt(&cpu_gdt_descr[0]);
+ per_cpu(cpu_gdt_descr, 0).address =
+ (unsigned long)__va(per_cpu(cpu_gdt_descr, 0).address);
+ load_gdt((struct Xgt_desc_struct *)__va(&per_cpu(cpu_gdt_descr, 0)));
+
cr4 = read_cr4();
if (cr4 & X86_CR4_PSE) {
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 5884469f6bfe..e0b7c632efbc 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -398,7 +398,11 @@ ignore_int:
pushl 32(%esp)
pushl 40(%esp)
pushl $int_msg
+#ifdef CONFIG_EARLY_PRINTK
+ call early_printk
+#else
call printk
+#endif
addl $(5*4),%esp
popl %ds
popl %es
@@ -530,5 +534,3 @@ ENTRY(cpu_gdt_table)
.quad 0x0000000000000000 /* 0xf0 - unused */
.quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
- /* Be sure this is zeroed to avoid false validations in Xen */
- .fill PAGE_SIZE_asm / 8 - GDT_ENTRIES,8,0
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 3999bec50c33..055325056a74 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -3,8 +3,6 @@
#include <asm/checksum.h>
#include <asm/desc.h>
-EXPORT_SYMBOL_GPL(cpu_gdt_descr);
-
EXPORT_SYMBOL(__down_failed);
EXPORT_SYMBOL(__down_failed_interruptible);
EXPORT_SYMBOL(__down_failed_trylock);
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index f2dd218d88cb..235822b3f41b 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -2566,8 +2566,10 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
spin_unlock_irqrestore(&ioapic_lock, flags);
/* Sanity check */
- if (reg_00.bits.ID != apic_id)
- panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
+ if (reg_00.bits.ID != apic_id) {
+ printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
+ return -1;
+ }
}
apic_printk(APIC_VERBOSE, KERN_INFO
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 6483eeb1a4e8..694a13997637 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
+ /* insn: must be on special executable page on i386. */
+ p->ainsn.insn = get_insn_slot();
+ if (!p->ainsn.insn)
+ return -ENOMEM;
+
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
return 0;
@@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+ down(&kprobe_mutex);
+ free_insn_slot(p->ainsn.insn);
+ up(&kprobe_mutex);
+}
+
static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kcb->prev_kprobe.kp = kprobe_running();
@@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
if (p->opcode == BREAKPOINT_INSTRUCTION)
regs->eip = (unsigned long)p->addr;
else
- regs->eip = (unsigned long)&p->ainsn.insn;
+ regs->eip = (unsigned long)p->ainsn.insn;
}
/* Called with kretprobe_lock held */
@@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p,
{
unsigned long *tos = (unsigned long *)&regs->esp;
unsigned long next_eip = 0;
- unsigned long copy_eip = (unsigned long)&p->ainsn.insn;
+ unsigned long copy_eip = (unsigned long)p->ainsn.insn;
unsigned long orig_eip = (unsigned long)p->addr;
switch (p->ainsn.insn[0]) {
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 0102f3d50e57..e6e2f43db85e 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -710,7 +710,7 @@ void __init get_smp_config (void)
* Read the physical hardware table. Anything here will
* override the defaults.
*/
- if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+ if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr))) {
smp_found_config = 0;
printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
@@ -915,6 +915,7 @@ void __init mp_register_ioapic (
u32 gsi_base)
{
int idx = 0;
+ int tmpid;
if (nr_ioapics >= MAX_IO_APICS) {
printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
@@ -935,9 +936,14 @@ void __init mp_register_ioapic (
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 < 15))
- mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id);
+ tmpid = io_apic_get_unique_id(idx, id);
else
- mp_ioapics[idx].mpc_apicid = id;
+ tmpid = id;
+ if (tmpid == -1) {
+ nr_ioapics--;
+ return;
+ }
+ mp_ioapics[idx].mpc_apicid = tmpid;
mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
/*
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 255adb498268..eba7f53f8b4a 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -87,11 +87,7 @@ EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_callin_map;
cpumask_t cpu_callout_map;
EXPORT_SYMBOL(cpu_callout_map);
-#ifdef CONFIG_HOTPLUG_CPU
-cpumask_t cpu_possible_map = CPU_MASK_ALL;
-#else
cpumask_t cpu_possible_map;
-#endif
EXPORT_SYMBOL(cpu_possible_map);
static cpumask_t smp_commenced_mask;
@@ -902,12 +898,6 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
unsigned long start_eip;
unsigned short nmi_high = 0, nmi_low = 0;
- if (!cpu_gdt_descr[cpu].address &&
- !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
- printk("Failed to allocate GDT for CPU %d\n", cpu);
- return 1;
- }
-
++cpucount;
/*
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 5a8b3fb6d27b..ac687d00a1ce 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -299,7 +299,7 @@ ENTRY(sys_call_table)
.long sys_mknodat
.long sys_fchownat
.long sys_futimesat
- .long sys_newfstatat /* 300 */
+ .long sys_fstatat64 /* 300 */
.long sys_unlinkat
.long sys_renameat
.long sys_linkat
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
index 7c86e3c5f1c1..a7f5a2aceba2 100644
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -282,6 +282,10 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
if (val != CPUFREQ_RESUMECHANGE)
write_seqlock_irq(&xtime_lock);
if (!ref_freq) {
+ if (!freq->old){
+ ref_freq = freq->new;
+ goto end;
+ }
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
#ifndef CONFIG_SMP
@@ -307,6 +311,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
#endif
}
+end:
if (val != CPUFREQ_RESUMECHANGE)
write_sequnlock_irq(&xtime_lock);
diff --git a/arch/i386/kernel/topology.c b/arch/i386/kernel/topology.c
new file mode 100644
index 000000000000..67a0e1baa28b
--- /dev/null
+++ b/arch/i386/kernel/topology.c
@@ -0,0 +1,97 @@
+/*
+ * arch/i386/kernel/topology.c - Populate driverfs with topology information
+ *
+ * Written by: Matthew Dobson, IBM Corporation
+ * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL
+ *
+ * Copyright (C) 2002, IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <colpatch@us.ibm.com>
+ */
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/nodemask.h>
+#include <asm/cpu.h>
+
+static struct i386_cpu cpu_devices[NR_CPUS];
+
+int arch_register_cpu(int num){
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return register_cpu(&cpu_devices[num].cpu, num, parent);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void arch_unregister_cpu(int num) {
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return unregister_cpu(&cpu_devices[num].cpu, parent);
+}
+EXPORT_SYMBOL(arch_register_cpu);
+EXPORT_SYMBOL(arch_unregister_cpu);
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+
+
+#ifdef CONFIG_NUMA
+#include <linux/mmzone.h>
+#include <asm/node.h>
+
+struct i386_node node_devices[MAX_NUMNODES];
+
+static int __init topology_init(void)
+{
+ int i;
+
+ for_each_online_node(i)
+ arch_register_node(i);
+
+ for_each_present_cpu(i)
+ arch_register_cpu(i);
+ return 0;
+}
+
+#else /* !CONFIG_NUMA */
+
+static int __init topology_init(void)
+{
+ int i;
+
+ for_each_present_cpu(i)
+ arch_register_cpu(i);
+ return 0;
+}
+
+#endif /* CONFIG_NUMA */
+
+subsys_initcall(topology_init);
diff --git a/arch/i386/kernel/vsyscall-sysenter.S b/arch/i386/kernel/vsyscall-sysenter.S
index 4daefb2ec1b2..76b728159403 100644
--- a/arch/i386/kernel/vsyscall-sysenter.S
+++ b/arch/i386/kernel/vsyscall-sysenter.S
@@ -7,6 +7,21 @@
* for details.
*/
+/*
+ * The caller puts arg2 in %ecx, which gets pushed. The kernel will use
+ * %ecx itself for arg2. The pushing is because the sysexit instruction
+ * (found in entry.S) requires that we clobber %ecx with the desired %esp.
+ * User code might expect that %ecx is unclobbered though, as it would be
+ * for returning via the iret instruction, so we must push and pop.
+ *
+ * The caller puts arg3 in %edx, which the sysexit instruction requires
+ * for %eip. Thus, exactly as for arg2, we must push and pop.
+ *
+ * Arg6 is different. The caller puts arg6 in %ebp. Since the sysenter
+ * instruction clobbers %esp, the user's %esp won't even survive entry
+ * into the kernel. We store %esp in %ebp. Code in entry.S must fetch
+ * arg6 from the stack.
+ */
.text
.globl __kernel_vsyscall
.type __kernel_vsyscall,@function
OpenPOWER on IntegriCloud