Commit cf34d923 authored by Andi Kleen's avatar Andi Kleen Committed by Christoph Hellwig

[PATCH] x86_64 update

x86-64 updates for 2.5.58. Changes only x86-64 specific files.

 - Rewrote module allocation. Lots of bugs fixed. Module loading
   should work now again.
 - Kconfig help fixes from Randy Dunlap
 - Makefile cleanups from Pavel Machek and Sam Ravnborg
 - Assembly cleanups from Pavel
 - defconfig update
 - Better strlen_user/strnlen_user
 - Merge with i386: new ptrace commands, 32bit vsyscall signal trampolines
		new deactivate_mm, add asm/bug.h
 - Make sure initramfs is freed after booting (thanks to Kai for the hint)
 - User per cpu data for profile counters (Ravikiran Thirumalai)
 - 32bit compat_* updates from Stephen Rothwell
 - Fix race in context switch. The exception handler for bogus segment
   loads in __switch_to needs to keep interrupts disabled, otherwise an
   interrupt can deadlock on scheduler locks.  Also make sure they don't
   printk or set oops_in_progress during printk because printk does a
   wake_up too.
 - Disable 64bit GS base changes for processes.  I cannot get it to work
   reliably.
 - Clear IOPL on kernel entry
parent 188db2b9
This diff is collapsed.
......@@ -54,35 +54,31 @@ libs-y += arch/x86_64/lib/
core-y += arch/x86_64/kernel/ arch/x86_64/mm/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
# FIXME: is drivers- right ?
drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/x86_64/boot $(1)
boot := arch/x86_64/boot
.PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
clean archclean archmrproper
.PHONY: bzImage bzlilo bzdisk install archmrproper
BOOTIMAGE=arch/x86_64/boot/bzImage
zImage zlilo zdisk: BOOTIMAGE=arch/x86_64/boot/zImage
#Default target when executing "make"
all: bzImage
zImage bzImage: vmlinux
$(call makeboot,$(BOOTIMAGE))
BOOTIMAGE := arch/x86_64/boot/bzImage
compressed: zImage
bzImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
zlilo bzlilo: vmlinux
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zlilo)
bzlilo: vmlinux
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) zlilo
zdisk bzdisk: vmlinux
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) zdisk)
bzdisk: vmlinux
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) zdisk
install: vmlinux
$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install)
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
archclean:
$(Q)$(MAKE) $(clean)=arch/i386/boot
archmrproper:
$(Q)$(MAKE) $(clean)=$(boot)
prepare: include/asm-$(ARCH)/offset.h
......@@ -90,10 +86,10 @@ arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
include/config/MARKER
include/asm-$(ARCH)/offset.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s
@$(generate-asm-offsets.h) < $< > $@
include/asm-$(ARCH)/offset.h: include/asm-$(ARCH)/offset.h.tmp
include/asm-$(ARCH)/offset.h: arch/$(ARCH)/kernel/asm-offsets.s
@echo -n ' Generating $@'
@$(generate-asm-offsets.h) < $< > $@.tmp
@$(update-if-changed)
CLEAN_FILES += include/asm-$(ARCH)/offset.h.tmp \
......
......@@ -26,16 +26,14 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
#RAMDISK := -DRAMDISK=512
EXTRA_TARGETS := vmlinux.bin bootsect bootsect.o \
setup setup.o zImage bzImage
setup setup.o bzImage
CFLAGS += -m32
EXTRA_CFLAGS := -m32
host-progs := tools/build
subdir- := compressed #Let make clean descend in compressed/
subdir- := compressed/ #Let make clean descend in compressed/
# ---------------------------------------------------------------------------
$(obj)/zImage: IMAGE_OFFSET := 0x1000
$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
$(obj)/bzImage: IMAGE_OFFSET := 0x100000
$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
......@@ -44,7 +42,7 @@ quiet_cmd_image = BUILD $@
cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
$(obj)/vmlinux.bin $(ROOT_DEV) > $@
$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
$(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
$(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
@echo 'Kernel: $@ is ready'
......
......@@ -11,7 +11,7 @@ EXTRA_AFLAGS := -traditional -m32
# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
# -m32
CFLAGS := -m32 -D__KERNEL__ -I$(TOPDIR)/include -O2
CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2
LDFLAGS := -m elf_i386
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
......
......@@ -19,10 +19,16 @@ CONFIG_EXPERIMENTAL=y
#
# General setup
#
CONFIG_NET=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_LOG_BUF_SHIFT_17 is not set
CONFIG_LOG_BUF_SHIFT_16=y
# CONFIG_LOG_BUF_SHIFT_15 is not set
# CONFIG_LOG_BUF_SHIFT_14 is not set
# CONFIG_LOG_BUF_SHIFT_13 is not set
# CONFIG_LOG_BUF_SHIFT_12 is not set
CONFIG_LOG_BUF_SHIFT=16
#
# Loadable module support
......@@ -85,6 +91,7 @@ CONFIG_ACPI_SYSTEM=y
#
CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
# CONFIG_PCI_LEGACY_PROC is not set
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
......@@ -163,15 +170,14 @@ CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
CONFIG_BLK_DEV_AMD74XX=y
# CONFIG_AMD74XX_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_NFORCE is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
......@@ -211,6 +217,11 @@ CONFIG_BLK_DEV_IDE_MODES=y
#
# CONFIG_IEEE1394 is not set
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
......@@ -263,10 +274,6 @@ CONFIG_IPV6_SCTP__=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
#
# Network device support
#
CONFIG_NETDEVICES=y
#
......@@ -286,8 +293,6 @@ CONFIG_NET_ETHERNET=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
#
# Tulip family network device support
......@@ -296,6 +301,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
CONFIG_AMD8111_ETH=y
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_DGRS is not set
......@@ -315,7 +321,6 @@ CONFIG_8139TOO=m
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
......@@ -343,7 +348,6 @@ CONFIG_TIGON3=y
#
# Token Ring devices (depends on LLC=y)
#
# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
......@@ -445,12 +449,25 @@ CONFIG_UNIX98_PTY_COUNT=256
#
# CONFIG_I2C is not set
#
# I2C Hardware Sensors Mainboard support
#
#
# I2C Hardware Sensors Chip support
#
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
......@@ -470,7 +487,6 @@ CONFIG_RTC=y
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_AGP_GART is not set
# CONFIG_AGP3 is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
CONFIG_RAW_DRIVER=y
......@@ -544,6 +560,7 @@ CONFIG_NFSD_V3=y
# CONFIG_NFSD_V4 is not set
CONFIG_NFSD_TCP=y
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_GSS is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
......
......@@ -80,9 +80,9 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
int err;
__u32 v;
err = __get_user(fxsave->cwd, (u16 *)&buf->cw);
err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
err = __get_user(fxsave->cwd, &buf->cw);
err |= __get_user(fxsave->swd, &buf->sw);
err |= __get_user(fxsave->twd, &buf->tag);
fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
err |= __get_user(fxsave->rip, &buf->ipoff);
err |= __get_user(fxsave->rdp, &buf->dataoff);
......
......@@ -31,6 +31,7 @@
#include <asm/user32.h>
#include <asm/sigcontext32.h>
#include <asm/fpu32.h>
#include <asm/proto.h>
#define ptr_to_u32(x) ((u32)(u64)(x)) /* avoid gcc warning */
......@@ -405,18 +406,30 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
if (err)
goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
} else {
err |= __put_user((u32)(u64)frame->retcode, &frame->pretcode);
/* This is popl %eax ; movl $,%eax ; int $0x80 */
err |= __put_user((u16)0xb858, (short *)(frame->retcode+0));
err |= __put_user((u32)__NR_ia32_sigreturn, (int *)(frame->retcode+2));
err |= __put_user((u16)0x80cd, (short *)(frame->retcode+6));
/* Return stub is in 32bit vsyscall page */
{
void *restorer = syscall32_page + 32;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
err |= __put_user(ptr_to_u32(restorer), &frame->pretcode);
}
/* These are actually not used anymore, but left because some
gdb versions depend on them as a marker. */
{
/* copy_to_user optimizes that into a single 8 byte store */
static const struct {
u16 poplmovl;
u32 val;
u16 int80;
u16 pad;
} __attribute__((packed)) code = {
0xb858, /* popl %eax ; movl $...,%eax */
__NR_ia32_sigreturn,
0x80cd, /* int $0x80 */
0,
};
err |= __copy_to_user(frame->retcode, &code, 8);
}
if (err)
goto give_sigsegv;
......@@ -486,18 +499,33 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (err)
goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
err |= __put_user((u32)(u64)ka->sa.sa_restorer, &frame->pretcode);
} else {
err |= __put_user(ptr_to_u32(frame->retcode), &frame->pretcode);
/* This is movl $,%eax ; int $0x80 */
err |= __put_user(0xb8, (char *)(frame->retcode+0));
err |= __put_user((u32)__NR_ia32_rt_sigreturn, (int *)(frame->retcode+1));
err |= __put_user(0x80cd, (short *)(frame->retcode+5));
{
void *restorer = syscall32_page + 32;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
err |= __put_user(ptr_to_u32(restorer), &frame->pretcode);
}
/* This is movl $,%eax ; int $0x80 */
/* Not actually used anymore, but left because some gdb versions
need it. */
{
/* __copy_to_user optimizes that into a single 8 byte store */
static const struct {
u8 movl;
u32 val;
u16 int80;
u16 pad;
u8 pad2;
} __attribute__((packed)) code = {
0xb8,
__NR_ia32_rt_sigreturn,
0x80cd,
0,
};
err |= __copy_to_user(frame->retcode, &code, 8);
}
if (err)
goto give_sigsegv;
......
......@@ -248,7 +248,7 @@ ia32_sys_call_table:
.quad sys_brk /* 45 */
.quad sys_setgid16
.quad sys_getgid16
.quad ni_syscall /* signal */
.quad sys_signal
.quad sys_geteuid16
.quad sys_getegid16 /* 50 */
.quad sys_acct
......@@ -299,8 +299,8 @@ ia32_sys_call_table:
.quad sys_getpriority
.quad sys_setpriority
.quad ni_syscall /* old profil syscall holder */
.quad sys32_statfs
.quad sys32_fstatfs /* 100 */
.quad compat_sys_statfs
.quad compat_sys_fstatfs /* 100 */
.quad sys_ioperm
.quad sys32_socketcall
.quad sys_syslog
......
......@@ -404,58 +404,6 @@ sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset,
return 0;
}
static int
put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
{
if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct statfs32)) ||
__put_user (kbuf->f_type, &ubuf->f_type) ||
__put_user (kbuf->f_bsize, &ubuf->f_bsize) ||
__put_user (kbuf->f_blocks, &ubuf->f_blocks) ||
__put_user (kbuf->f_bfree, &ubuf->f_bfree) ||
__put_user (kbuf->f_bavail, &ubuf->f_bavail) ||
__put_user (kbuf->f_files, &ubuf->f_files) ||
__put_user (kbuf->f_ffree, &ubuf->f_ffree) ||
__put_user (kbuf->f_namelen, &ubuf->f_namelen) ||
__put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
__put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]))
return -EFAULT;
return 0;
}
extern asmlinkage long sys_statfs(const char * path, struct statfs * buf);
asmlinkage long
sys32_statfs(const char * path, struct statfs32 *buf)
{
int ret;
struct statfs s;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_statfs((const char *)path, &s);
set_fs (old_fs);
if (put_statfs(buf, &s))
return -EFAULT;
return ret;
}
extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);
asmlinkage long
sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
{
int ret;
struct statfs s;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_fstatfs(fd, &s);
set_fs (old_fs);
if (put_statfs(buf, &s))
return -EFAULT;
return ret;
}
static inline long
get_tv32(struct timeval *o, struct compat_timeval *i)
{
......
/* Copyright 2002 Andi Kleen, SuSE Labs */
/* Copyright 2002,2003 Andi Kleen, SuSE Labs */
/* vsyscall handling for 32bit processes. Map a stub page into it
on demand because 32bit cannot reach the kernel's fixmaps */
......@@ -8,8 +8,10 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/stringify.h>
#include <asm/proto.h>
#include <asm/tlbflush.h>
#include <asm/ia32_unistd.h>
/* 32bit SYSCALL stub mapped into user space. */
asm(" .code32\n"
......@@ -20,11 +22,26 @@ asm(" .code32\n"
" popl %ebp\n"
" ret\n"
"syscall32_end:\n"
/* signal trampolines */
"sig32_rt_tramp:\n"
" movl $" __stringify(__NR_ia32_rt_sigreturn) ",%eax\n"
" int $0x80\n"
"sig32_rt_tramp_end:\n"
"sig32_tramp:\n"
" popl %eax\n"
" movl $" __stringify(__NR_ia32_sigreturn) ",%eax\n"
" int $0x80\n"
"sig32_tramp_end:\n"
" .code64\n");
extern unsigned char syscall32[], syscall32_end[];
extern unsigned char sig32_rt_tramp[], sig32_rt_tramp_end[];
extern unsigned char sig32_tramp[], sig32_tramp_end[];
static unsigned long syscall32_page;
char *syscall32_page;
/* RED-PEN: This knows too much about high level VM */
/* Alternative would be to generate a vma with appropiate backing options
......@@ -54,11 +71,16 @@ int map_syscall32(struct mm_struct *mm, unsigned long address)
static int __init init_syscall32(void)
{
syscall32_page = get_zeroed_page(GFP_KERNEL);
syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
if (!syscall32_page)
panic("Cannot allocate syscall32 page");
SetPageReserved(virt_to_page(syscall32_page));
memcpy((void *)syscall32_page, syscall32, syscall32_end - syscall32);
memcpy(syscall32_page, syscall32, syscall32_end - syscall32);
memcpy(syscall32_page + 32, sig32_rt_tramp,
sig32_rt_tramp_end - sig32_rt_tramp);
memcpy(syscall32_page + 64, sig32_tramp,
sig32_tramp_end - sig32_tramp);
return 0;
}
__initcall(init_syscall32);
......@@ -3,7 +3,7 @@
#
EXTRA_TARGETS := head.o head64.o init_task.o
EXTRA_AFLAGS := -traditional
export-objs := x8664_ksyms.o pci-gart.o pci-dma.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
......@@ -32,4 +32,3 @@ $(obj)/bootflag.c:
clean-files += bootflag.c
EXTRA_AFLAGS := -traditional
......@@ -39,7 +39,7 @@ int dont_enable_local_apic __initdata = 0;
int prof_multiplier[NR_CPUS] = { 1, };
int prof_old_multiplier[NR_CPUS] = { 1, };
int prof_counter[NR_CPUS] = { 1, };
DEFINE_PER_CPU(int, prof_counter) = 1;
int get_maxlvt(void)
{
......@@ -901,7 +901,7 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs)
x86_do_profile(regs);
if (--prof_counter[cpu] <= 0) {
if (--per_cpu(prof_counter, cpu) <= 0) {
/*
* The multiplier may have changed since the last time we got
* to this point as a result of the user writing to
......@@ -910,10 +910,11 @@ inline void smp_local_timer_interrupt(struct pt_regs *regs)
*
* Interrupts are already masked off at this point.
*/
prof_counter[cpu] = prof_multiplier[cpu];
if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
__setup_APIC_LVTT(calibration_result/prof_counter[cpu]);
prof_old_multiplier[cpu] = prof_counter[cpu];
per_cpu(prof_counter, cpu) = prof_multiplier[cpu];
if (per_cpu(prof_counter, cpu) != prof_old_multiplier[cpu]) {
__setup_APIC_LVTT(calibration_result/
per_cpu(prof_counter, cpu));
prof_old_multiplier[cpu] = per_cpu(prof_counter, cpu);
}
#ifdef CONFIG_SMP
......
......@@ -532,8 +532,10 @@ error_swapgs:
xorl %ebx,%ebx
swapgs
error_sti:
bt $9,EFLAGS(%rsp)
jnc 1f
sti
movq %rdi,RDI(%rsp)
1: movq %rdi,RDI(%rsp)
movq %rsp,%rdi
movq ORIG_RAX(%rsp),%rsi /* get error code */
movq $-1,ORIG_RAX(%rsp)
......
......@@ -66,7 +66,7 @@ startup_32:
movl %eax, %cr4
/* Setup early boot stage 4 level pagetables */
movl $0x101000, %eax
movl $(init_level4_pgt - __START_KERNEL_map), %eax
movl %eax, %cr3
/* Setup EFER (Extended Feature Enable Register) */
......@@ -89,20 +89,13 @@ startup_32:
wrmsr
xorl %eax, %eax
/* Enable paging and in turn activate Long Mode */
btsl $31, %eax
/* Enable protected mode */
btsl $0, %eax
/* Enable MP */
btsl $1, %eax
/* Enable ET */
btsl $4, %eax
/* Enable NE */
btsl $5, %eax
/* Enable WP */
btsl $16, %eax
/* Enable AM */
btsl $18, %eax
btsl $31, %eax /* Enable paging and in turn activate Long Mode */
btsl $0, %eax /* Enable protected mode */
btsl $1, %eax /* Enable MP */
btsl $4, %eax /* Enable ET */
btsl $5, %eax /* Enable NE */
btsl $16, %eax /* Enable WP */
btsl $18, %eax /* Enable AM */
/* Make changes effective */
movl %eax, %cr0
jmp reach_compatibility_mode
......@@ -120,10 +113,10 @@ reach_compatibility_mode:
/* Load new GDT with the 64bit segment using 32bit descriptor */
/* to avoid 32bit relocations we use fixed adresses here */
movl $0x100F00, %eax
movl $(pGDT32 - __START_KERNEL_map), %eax
lgdt (%eax)
movl $0x100F10, %eax
movl $(ljumpvector - __START_KERNEL_map), %eax
/* Finally jump in 64bit mode */
ljmp *(%eax)
......@@ -205,11 +198,11 @@ ENTRY(no_long_mode)
.org 0xf00
pGDT32:
.word gdt32_end-gdt_table32
.long gdt_table32-__START_KERNEL+0x100000
.long gdt_table32-__START_KERNEL_map
.org 0xf10
ljumpvector:
.long reach_long64-__START_KERNEL+0x100000
.long reach_long64-__START_KERNEL_map
.word __KERNEL_CS
ENTRY(stext)
......
/* Kernel module help for x86-64
Copyright (C) 2001 Rusty Russell.
Copyright (C) 2002 Andi Kleen, SuSE Labs.
Copyright (C) 2002,2003 Andi Kleen, SuSE Labs.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -22,9 +22,115 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#define DEBUGP(fmt...)
void module_free(struct module *mod, void *module_region)
{
struct vm_struct **prevp, *map;
int i;
unsigned long addr = (unsigned long)module_region;
if (!addr)
return;
write_lock(&vmlist_lock);
for (prevp = &vmlist ; (map = *prevp) ; prevp = &map->next) {
if ((unsigned long)map->addr == addr) {
*prevp = map->next;
write_unlock(&vmlist_lock);
goto found;
}
}
write_unlock(&vmlist_lock);
printk("Trying to unmap nonexistent module vm area (%lx)\n", addr);
return;
found:
unmap_vm_area(map);
if (map->pages) {
for (i = 0; i < map->nr_pages; i++)
if (map->pages[i])
__free_page(map->pages[i]);
kfree(map->pages);
}
kfree(map);
}
void *module_alloc(unsigned long size)
{
struct vm_struct **p, *tmp, *area;
struct page **pages;
void *addr;
unsigned int nr_pages, array_size, i;
if (!size)
return NULL;
size = PAGE_ALIGN(size);
if (size > MODULES_LEN)
return NULL;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
memset(area, 0, sizeof(struct vm_struct));
write_lock(&vmlist_lock);
addr = (void *) MODULES_VADDR;
for (p = &vmlist; (tmp = *p); p = &tmp->next) {
void *next;
DEBUGP("vmlist %p %lu addr %p\n", tmp->addr, tmp->size, addr);
if (size + (unsigned long) addr + PAGE_SIZE < (unsigned long) tmp->addr)
break;
next = (void *) (tmp->size + (unsigned long) tmp->addr);
if (next > addr)
addr = next;
}
if ((unsigned long)addr + size >= MODULES_END) {
write_unlock(&vmlist_lock);
kfree(area);
return NULL;
}
DEBUGP("addr %p\n", addr);
area->next = *p;
*p = area;
area->size = size + PAGE_SIZE;
area->addr = addr;
write_unlock(&vmlist_lock);
nr_pages = size >> PAGE_SHIFT;
array_size = (nr_pages * sizeof(struct page *));
area->nr_pages = nr_pages;
area->pages = pages = kmalloc(array_size, GFP_KERNEL);
if (!area->pages)
goto fail;
memset(area->pages, 0, array_size);
for (i = 0; i < nr_pages; i++) {
area->pages[i] = alloc_page(GFP_KERNEL);
if (area->pages[i] == NULL)
goto fail;
}
if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages))
goto fail;
memset(addr, 0, size);
DEBUGP("module_alloc size %lu = %p\n", size, addr);
return addr;
fail:
module_free(NULL, addr);
return NULL;
}
/* We don't need anything special. */
int module_frob_arch_sections(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs,
......
......@@ -537,6 +537,11 @@ int sys_arch_prctl(int code, unsigned long addr)
switch (code) {
case ARCH_SET_GS:
#if 1
/* For now. We still have one unsolved bug in long gs base context
switch handling. */
return -EINVAL;
#else
if (addr >= TASK_SIZE)
return -EPERM;
get_cpu();
......@@ -546,6 +551,7 @@ int sys_arch_prctl(int code, unsigned long addr)
ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
put_cpu();
break;
#endif
case ARCH_SET_FS:
/* Not strictly needed for fs, but do it for symmetry
with gs */
......@@ -594,15 +600,15 @@ static int get_free_idx(void)
* Set a given TLS descriptor:
* When you want addresses > 32bit use arch_prctl()
*/
asmlinkage int sys_set_thread_area(struct user_desc *u_info)
int do_set_thread_area(struct thread_struct *t, struct user_desc *u_info)
{
struct thread_struct *t = &current->thread;
struct user_desc info;
struct n_desc_struct *desc;
int cpu, idx;
if (copy_from_user(&info, u_info, sizeof(info)))
return -EFAULT;
idx = info.entry_number;
/*
......@@ -634,12 +640,19 @@ asmlinkage int sys_set_thread_area(struct user_desc *u_info)
desc->a = LDT_entry_a(&info);
desc->b = LDT_entry_b(&info);
}
if (t == &current->thread)
load_TLS(t, cpu);
put_cpu();
return 0;
}
asmlinkage int sys_set_thread_area(struct user_desc *u_info)
{
return do_set_thread_area(&current->thread, u_info);
}
/*
* Get the current Thread-Local Storage area:
*/
......@@ -661,7 +674,7 @@ asmlinkage int sys_set_thread_area(struct user_desc *u_info)
#define GET_USEABLE(desc) (((desc)->b >> 20) & 1)
#define GET_LONGMODE(desc) (((desc)->b >> 21) & 1)
asmlinkage int sys_get_thread_area(struct user_desc *u_info)
int do_get_thread_area(struct thread_struct *t, struct user_desc *u_info)
{
struct user_desc info;
struct n_desc_struct *desc;
......@@ -672,7 +685,7 @@ asmlinkage int sys_get_thread_area(struct user_desc *u_info)
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;
desc = ((struct n_desc_struct *)current->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN;
desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
memset(&info, 0, sizeof(struct user_desc));
info.entry_number = idx;
......@@ -691,6 +704,11 @@ asmlinkage int sys_get_thread_area(struct user_desc *u_info)
return 0;
}
asmlinkage int sys_get_thread_area(struct user_desc *u_info)
{
return do_get_thread_area(&current->thread, u_info);
}
/*
* Capture the user space registers if the task is not running (in user space)
*/
......
......@@ -23,6 +23,9 @@
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/debugreg.h>
#include <asm/ldt.h>
#include <asm/desc.h>
#include <asm/proto.h>
/*
* does not yet catch signals sent when the child dies.
......@@ -319,6 +322,22 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
wake_up_process(child);
ret = 0;
break;
case PTRACE_SET_THREAD_AREA: {
int old;
get_user(old, &((struct user_desc *)data)->entry_number);
put_user(addr, &((struct user_desc *)data)->entry_number);
ret = do_set_thread_area(&child->thread,
(struct user_desc *)data);
put_user(old, &((struct user_desc *)data)->entry_number);
break;
case PTRACE_GET_THREAD_AREA:
get_user(old, &((struct user_desc *)data)->entry_number);
put_user(addr, &((struct user_desc *)data)->entry_number);
ret = do_get_thread_area(&child->thread,
(struct user_desc *)data);
put_user(old, &((struct user_desc *)data)->entry_number);
break;
}
}
/*
......
......@@ -200,7 +200,7 @@ void __init cpu_init (void)
#endif
/* Flags to clear on syscall */
wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE);
wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000);
wrmsrl(MSR_FS_BASE, 0);
wrmsrl(MSR_KERNEL_GS_BASE, 0);
......
......@@ -772,24 +772,16 @@ static void smp_tune_scheduling (void)
* Cycle through the processors sending APIC IPIs to boot each.
*/
extern int prof_multiplier[NR_CPUS];
extern int prof_old_multiplier[NR_CPUS];
extern int prof_counter[NR_CPUS];
static void __init smp_boot_cpus(unsigned int max_cpus)
{
int apicid, cpu;
/*
* Initialize the logical to physical CPU number mapping
* and the per-CPU profiling counter/multiplier
*/
for (apicid = 0; apicid < NR_CPUS; apicid++) {
x86_apicid_to_cpu[apicid] = -1;
prof_counter[apicid] = 1;
prof_old_multiplier[apicid] = 1;
prof_multiplier[apicid] = 1;
}
/*
......
......@@ -450,16 +450,20 @@ asmlinkage void do_int3(struct pt_regs * regs, long error_code)
do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
}
extern void dump_pagetable(unsigned long);
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
#ifdef CONFIG_CHECKING
{
unsigned long gs;
struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
struct x8664_pda *pda = cpu_pda + hard_smp_processor_id();
rdmsrl(MSR_GS_BASE, gs);
if (gs != (unsigned long)pda) {
wrmsrl(MSR_GS_BASE, pda);
oops_in_progress++;
printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
oops_in_progress--;
}
}
#endif
......
......@@ -2,18 +2,15 @@
# Makefile for x86_64-specific library files.
#
EXTRA_CFLAGS_csum-partial.o := -funroll-loops
L_TARGET := lib.a
export-objs := io.o csum-wrappers.o csum-partial.o
CFLAGS_csum-partial.o := -funroll-loops
L_TARGET = lib.a
obj-y = csum-partial.o csum-copy.o csum-wrappers.o delay.o \
obj-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \
usercopy.o getuser.o putuser.o \
thunk.o io.o clear_page.o copy_page.o bitstr.o
obj-y += memcpy.o
obj-y += memmove.o
obj-y += memset.o
obj-y += copy_user.o
export-objs := io.o csum-wrappers.o csum-partial.o
obj-y += memcpy.o memmove.o memset.o copy_user.o
obj-$(CONFIG_IO_DEBUG) += iodebug.o
obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
......@@ -109,19 +109,34 @@ unsigned long clear_user(void *to, unsigned long n)
long strnlen_user(const char *s, long n)
{
unsigned long res = 0;
long res = 0;
char c;
if (!access_ok(VERIFY_READ, s, n))
return 0;
while (1) {
if (res>n)
return n+1;
if (__get_user(c, s))
return 0;
if (!c)
return res+1;
res++;
s++;
}
}
long strlen_user(const char *s)
{
long res = 0;
char c;
for (;;) {
if (get_user(c, s))
return 0;
if (!c)
return res+1;
if (res>n)
return n+1;
res++;
s++;
}
......
......@@ -4,5 +4,5 @@
export-objs := pageattr.o
obj-y := init.o fault.o ioremap.o extable.o modutil.o pageattr.o
obj-y := init.o fault.o ioremap.o extable.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
......@@ -161,7 +161,6 @@ static struct temp_map {
} temp_mappings[] __initdata = {
{ &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) },
{ &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) },
{ &temp_boot_pmds[2], (void *)(44UL * 1024 * 1024) },
{}
};
......@@ -316,8 +315,6 @@ void __init mem_init(void)
int codesize, reservedpages, datasize, initsize;
int tmp;
printk("mem_init\n");
if (!mem_map)
BUG();
......
/* arch/x86_64/mm/modutil.c
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Based upon code written by Linus Torvalds and others.
*
* Blatantly copied from sparc64 for x86-64 by Andi Kleen.
* Should use direct mapping with 2MB pages. This would need extension
* of the kernel mapping.
*/
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
void module_free(struct module *mod, void *module_region)
{
struct vm_struct **p, *tmp;
int i;
unsigned long addr = (unsigned long)module_region;
if (!addr)
return;
if ((PAGE_SIZE-1) & addr) {
printk("Trying to unmap module with bad address (%lx)\n", addr);
return;
}
write_lock(&vmlist_lock);
for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
if ((unsigned long)tmp->addr == addr) {
*p = tmp->next;
write_unlock(&vmlist_lock);
goto found;
}
}
write_unlock(&vmlist_lock);
printk("Trying to unmap nonexistent module vm area (%lx)\n", addr);
return;
found:
unmap_vm_area(tmp);
for (i = 0; i < tmp->nr_pages; i++) {
if (unlikely(!tmp->pages[i]))
BUG();
__free_page(tmp->pages[i]);
}
kfree(tmp->pages);
kfree(tmp);
}
void * module_alloc (unsigned long size)
{
struct vm_struct **p, *tmp, *area;
struct page **pages;
void * addr;
unsigned int nr_pages, array_size, i;
if (!size)
return NULL;
size = PAGE_ALIGN(size);
if (size > MODULES_LEN)
return ERR_PTR(-ENOMEM);
addr = (void *) MODULES_VADDR;
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
if ((unsigned long) addr + size >= MODULES_END)
return ERR_PTR(-ENOMEM);
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return ERR_PTR(-ENOMEM);
area->size = size + PAGE_SIZE;
area->addr = addr;
area->next = *p;
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
*p = area;
nr_pages = size >> PAGE_SHIFT;
array_size = (nr_pages * sizeof(struct page *));
area->nr_pages = nr_pages;
area->pages = pages = kmalloc(array_size, GFP_KERNEL);
if (!area->pages)
goto fail;
memset(area->pages, 0, array_size);
for (i = 0; i < area->nr_pages; i++) {
area->pages[i] = alloc_page(GFP_KERNEL);
if (unlikely(!area->pages[i]))
goto fail;
}
if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages)) {
unmap_vm_area(area);
goto fail;
}
memset(area->addr, 0, size);
return area->addr;
fail:
if (area->pages) {
for (i = 0; i < area->nr_pages; i++) {
if (area->pages[i])
__free_page(area->pages[i]);
}
kfree(area->pages);
}
kfree(area);
return ERR_PTR(-ENOMEM);
}
#
# Makefile for X86_64 specific PCI routines
#
obj-y := x86-64.o
obj-$(CONFIG_PCI_DIRECT) += direct.o
obj-$(CONFIG_PCI_DIRECT)+= direct.o
obj-y += fixup.o
ifdef CONFIG_ACPI_PCI
obj-y += acpi.o
endif
obj-y += legacy.o
obj-y += irq.o common.o
obj-$(CONFIG_ACPI_PCI) += acpi.o
obj-y += legacy.o irq.o common.o
......@@ -73,11 +73,6 @@ SECTIONS
. = ALIGN(4096);
.data.boot_pgt : { *(.data.boot_pgt) }
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.init.text : { *(.init.text) }
......@@ -100,6 +95,10 @@ SECTIONS
*(.initcall7.init)
}
__initcall_end = .;
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(32);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
......
#ifndef __ASM_X8664_BUG_H
#define __ASM_X8664_BUG_H 1
#include <linux/stringify.h>
/*
* Tell the user there is some problem. The exception handler decodes
* this frame.
*/
struct bug_frame {
unsigned char ud2[2];
/* should use 32bit offset instead, but the assembler doesn't
like it */
char *filename;
unsigned short line;
} __attribute__((packed));
#define BUG() \
asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \
"i"(__LINE__), "i" (__stringify(KBUILD_BASENAME)))
#define PAGE_BUG(page) BUG()
void out_of_line_bug(void);
#endif
......@@ -68,4 +68,17 @@ struct compat_flock {
compat_pid_t l_pid;
};
struct compat_statfs {
int f_type;
int f_bsize;
int f_blocks;
int f_bfree;
int f_bavail;
int f_files;
int f_ffree;
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_spare[6];
};
#endif /* _ASM_X86_64_COMPAT_H */
......@@ -101,19 +101,6 @@ struct stat64 {
} __attribute__((packed));
struct statfs32 {
int f_type;
int f_bsize;
int f_blocks;
int f_bfree;
int f_bavail;
int f_files;
int f_ffree;
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_spare[6];
};
typedef union sigval32 {
int sival_int;
unsigned int sival_ptr;
......
......@@ -62,7 +62,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
#endif
}
#define deactivate_mm(tsk,mm) do { } while (0)
#define deactivate_mm(tsk,mm) do { \
load_gs_index(0); \
asm volatile("movl %0,%%fs"::"r"(0)); \
} while(0)
#define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id())
......
......@@ -69,21 +69,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#ifndef __ASSEMBLY__
#include <linux/stringify.h>
/*
* Tell the user there is some problem. The exception handler decodes this frame.
*/
struct bug_frame {
unsigned char ud2[2];
char *filename; /* should use 32bit offset instead, but the assembler doesn't like it */
unsigned short line;
} __attribute__((packed));
#define BUG() \
asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \
"i"(__LINE__), "i" (__stringify(KBUILD_BASENAME)))
#define PAGE_BUG(page) BUG()
void out_of_line_bug(void);
#include <asm/bug.h>
/* Pure 2^n version of get_order */
extern __inline__ int get_order(unsigned long size)
......
......@@ -43,6 +43,12 @@ extern void exception_table_check(void);
extern int acpi_boot_init(char *);
extern int map_syscall32(struct mm_struct *mm, unsigned long address);
extern char *syscall32_page;
struct thread_struct;
int do_set_thread_area(struct thread_struct *t, struct user_desc *u_info);
int do_get_thread_area(struct thread_struct *t, struct user_desc *u_info);
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define round_down(x,y) ((x) & ~((y)-1))
......
......@@ -78,6 +78,10 @@ struct pt_regs {
#define PTRACE_GETFPXREGS 18
#define PTRACE_SETFPXREGS 19
#define PTRACE_GET_THREAD_AREA 25
#define PTRACE_SET_THREAD_AREA 26
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
#define user_mode(regs) (!!((regs)->cs & 3))
#define instruction_pointer(regs) ((regs)->rip)
......
......@@ -10,7 +10,7 @@
/*
* we cannot use the same code segment descriptor for user and kernel
* even not in the long flat model, because of different DPL /kkeil
* -- not even in the long flat mode, because of different DPL /kkeil
* The segment offset needs to contain a RPL. Grr. -AK
* GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets)
*/
......
......@@ -299,8 +299,8 @@ static inline int __copy_to_user(void *dst, const void *src, unsigned size)
long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count);
#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
long strnlen_user(const char *str, long n);
long strlen_user(const char *str);
unsigned long clear_user(void *mem, unsigned long len);
unsigned long __clear_user(void *mem, unsigned long len);
......
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