summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-06-01 03:16:17 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-06-01 03:16:17 +0000
commitd8d9b8f76f22b7a16a83e261e64f89ee611f49df (patch)
tree3067bc130b80d52808e6390c9fc7fc087ec1e33c /arch
parent19c9bba94152148523ba0f7ef7cffe3d45656b11 (diff)
Initial revision
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/defconfig32
-rw-r--r--arch/alpha/kernel/entry.S31
-rw-r--r--arch/alpha/kernel/head.S24
-rw-r--r--arch/alpha/kernel/process.c20
-rw-r--r--arch/alpha/kernel/ptrace.c35
-rw-r--r--arch/alpha/kernel/setup.c2
-rw-r--r--arch/alpha/mm/fault.c2
-rw-r--r--arch/alpha/mm/init.c3
-rw-r--r--arch/alpha/vmlinux.lds6
-rw-r--r--arch/i386/Makefile4
-rw-r--r--arch/i386/boot/video.S13
-rw-r--r--arch/i386/defconfig1
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/bios32.c72
-rw-r--r--arch/i386/kernel/entry.S81
-rw-r--r--arch/i386/kernel/head.S136
-rw-r--r--arch/i386/kernel/i386_ksyms.c10
-rw-r--r--arch/i386/kernel/init_task.c22
-rw-r--r--arch/i386/kernel/irq.c271
-rw-r--r--arch/i386/kernel/irq.h187
-rw-r--r--arch/i386/kernel/process.c26
-rw-r--r--arch/i386/kernel/ptrace.c28
-rw-r--r--arch/i386/kernel/setup.c14
-rw-r--r--arch/i386/kernel/signal.c10
-rw-r--r--arch/i386/kernel/smp.c773
-rw-r--r--arch/i386/kernel/time.c7
-rw-r--r--arch/i386/kernel/trampoline.S43
-rw-r--r--arch/i386/kernel/traps.c77
-rw-r--r--arch/i386/kernel/vm86.c20
-rw-r--r--arch/i386/lib/locks.S5
-rw-r--r--arch/i386/lib/semaphore.S8
-rw-r--r--arch/i386/mm/fault.c15
-rw-r--r--arch/i386/mm/init.c23
-rw-r--r--arch/i386/vmlinux.lds1
-rw-r--r--arch/m68k/Makefile14
-rw-r--r--arch/m68k/amiga/amifb.c6
-rw-r--r--arch/m68k/amiga/amiints.c3
-rw-r--r--arch/m68k/amiga/amikeyb.c3
-rw-r--r--arch/m68k/amiga/amisound.c5
-rw-r--r--arch/m68k/amiga/chipram.c10
-rw-r--r--arch/m68k/amiga/cia.c3
-rw-r--r--arch/m68k/amiga/config.c9
-rw-r--r--arch/m68k/amiga/cyberfb.c7
-rw-r--r--arch/m68k/amiga/retz3fb.c1754
-rw-r--r--arch/m68k/amiga/retz3fb.h286
-rw-r--r--arch/m68k/amiga/zorro.c10
-rw-r--r--arch/m68k/atari/atafb.c5
-rw-r--r--arch/m68k/atari/ataints.c21
-rw-r--r--arch/m68k/atari/atakeyb.c3
-rw-r--r--arch/m68k/atari/config.c21
-rw-r--r--arch/m68k/atari/joystick.c3
-rw-r--r--arch/m68k/atari/stdma.c4
-rw-r--r--arch/m68k/atari/stram.c3
-rw-r--r--arch/m68k/boot/amiga/linuxboot.c17
-rw-r--r--arch/m68k/boot/amiga/linuxboot.h2
-rw-r--r--arch/m68k/fpsp040/skeleton.S26
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S15
-rw-r--r--arch/m68k/kernel/entry.S109
-rw-r--r--arch/m68k/kernel/head.S14
-rw-r--r--arch/m68k/kernel/ints.c3
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c4
-rw-r--r--arch/m68k/kernel/process.c39
-rw-r--r--arch/m68k/kernel/ptrace.c30
-rw-r--r--arch/m68k/kernel/setup.c29
-rw-r--r--arch/m68k/kernel/signal.c6
-rw-r--r--arch/m68k/kernel/sys_m68k.c5
-rw-r--r--arch/m68k/kernel/time.c21
-rw-r--r--arch/m68k/kernel/traps.c10
-rw-r--r--arch/m68k/lib/semaphore.S7
-rw-r--r--arch/m68k/mm/fault.c16
-rw-r--r--arch/m68k/mm/init.c42
-rw-r--r--arch/m68k/mm/memory.c8
-rw-r--r--arch/m68k/vmlinux.lds60
-rw-r--r--arch/mips/Makefile4
-rw-r--r--arch/mips/boot/Makefile6
-rw-r--r--arch/mips/boot/mkboot.c8
-rw-r--r--arch/mips/config.in32
-rw-r--r--arch/mips/defconfig1
-rw-r--r--arch/mips/deskstation/io.c68
-rw-r--r--arch/mips/deskstation/setup.c14
-rw-r--r--arch/mips/jazz/.cvsignore1
-rw-r--r--arch/mips/jazz/io.c136
-rw-r--r--arch/mips/jazz/setup.c11
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/entry.S5
-rw-r--r--arch/mips/kernel/head.S42
-rw-r--r--arch/mips/kernel/init_task.c22
-rw-r--r--arch/mips/kernel/irix5sys.h2
-rw-r--r--arch/mips/kernel/irixelf.c48
-rw-r--r--arch/mips/kernel/irixioctl.c2
-rw-r--r--arch/mips/kernel/irixsig.c50
-rw-r--r--arch/mips/kernel/irq.c8
-rw-r--r--arch/mips/kernel/pci.c7
-rw-r--r--arch/mips/kernel/process.c11
-rw-r--r--arch/mips/kernel/ptrace.c28
-rw-r--r--arch/mips/kernel/r2300_switch.S5
-rw-r--r--arch/mips/kernel/r4k_misc.S4
-rw-r--r--arch/mips/kernel/r4k_switch.S7
-rw-r--r--arch/mips/kernel/setup.c9
-rw-r--r--arch/mips/kernel/signal.c11
-rw-r--r--arch/mips/kernel/syscalls.h1
-rw-r--r--arch/mips/kernel/sysirix.c223
-rw-r--r--arch/mips/kernel/time.c3
-rw-r--r--arch/mips/kernel/traps.c9
-rw-r--r--arch/mips/mips/Makefile39
-rwxr-xr-xarch/mips/mips/mkprom25
-rw-r--r--arch/mips/mm/Makefile2
-rw-r--r--arch/mips/mm/fault.c2
-rw-r--r--arch/mips/mm/r4xx0.c40
-rw-r--r--arch/mips/mm/stack.c27
-rw-r--r--arch/mips/sgi/kernel/indy_int.c15
-rw-r--r--arch/mips/sgi/kernel/setup.c1
-rw-r--r--arch/mips/sgi/prom/misc.c14
-rw-r--r--arch/mips/sni/.cvsignore1
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/int-handler.S23
-rw-r--r--arch/mips/sni/io.c172
-rw-r--r--arch/mips/sni/pci.c23
-rw-r--r--arch/mips/sni/setup.c25
-rw-r--r--arch/mips/tools/.cvsignore1
-rw-r--r--arch/mips/tools/offset.c3
-rw-r--r--arch/mips/tools/offset.h89
-rw-r--r--arch/ppc/kernel/misc.S3
-rw-r--r--arch/ppc/kernel/process.c18
-rw-r--r--arch/ppc/kernel/ptrace.c14
-rw-r--r--arch/ppc/mm/init.c109
-rw-r--r--arch/sparc/Makefile4
-rw-r--r--arch/sparc/ap1000/bnet.c14
-rw-r--r--arch/sparc/ap1000/hw.c29
-rw-r--r--arch/sparc/ap1000/mpp.c1
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/etrap.S14
-rw-r--r--arch/sparc/kernel/head.S15
-rw-r--r--arch/sparc/kernel/init_task.c18
-rw-r--r--arch/sparc/kernel/irq.c180
-rw-r--r--arch/sparc/kernel/process.c46
-rw-r--r--arch/sparc/kernel/ptrace.c28
-rw-r--r--arch/sparc/kernel/setup.c5
-rw-r--r--arch/sparc/kernel/signal.c4
-rw-r--r--arch/sparc/kernel/smp.c234
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c37
-rw-r--r--arch/sparc/kernel/sys_sunos.c46
-rw-r--r--arch/sparc/kernel/systbls.S29
-rw-r--r--arch/sparc/kernel/tadpole.c2
-rw-r--r--arch/sparc/kernel/trampoline.S34
-rw-r--r--arch/sparc/kernel/wof.S15
-rw-r--r--arch/sparc/kernel/wuf.S16
-rw-r--r--arch/sparc/lib/Makefile6
-rw-r--r--arch/sparc/lib/blockops.S33
-rw-r--r--arch/sparc/lib/debuglocks.c463
-rw-r--r--arch/sparc/lib/irqlock.S2
-rw-r--r--arch/sparc/mm/Makefile22
-rw-r--r--arch/sparc/mm/asyncd.c7
-rw-r--r--arch/sparc/mm/fault.c6
-rw-r--r--arch/sparc/mm/hypersparc.S74
-rw-r--r--arch/sparc/mm/srmmu.c284
-rw-r--r--arch/sparc/mm/sun4c.c120
-rw-r--r--arch/sparc/mm/tsunami.S90
-rw-r--r--arch/sparc/mm/viking.S85
-rw-r--r--arch/sparc/prom/console.c18
-rw-r--r--arch/sparc/prom/devmap.c9
-rw-r--r--arch/sparc/prom/devops.c13
-rw-r--r--arch/sparc/prom/misc.c13
-rw-r--r--arch/sparc/prom/mp.c13
-rw-r--r--arch/sparc/prom/segment.c7
-rw-r--r--arch/sparc/prom/tree.c6
-rw-r--r--arch/sparc64/Makefile4
-rw-r--r--arch/sparc64/defconfig9
-rw-r--r--arch/sparc64/kernel/Makefile13
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c34
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S28
-rw-r--r--arch/sparc64/kernel/entry.S124
-rw-r--r--arch/sparc64/kernel/etrap.S109
-rw-r--r--arch/sparc64/kernel/hack.S16
-rw-r--r--arch/sparc64/kernel/head.S31
-rw-r--r--arch/sparc64/kernel/init_task.c18
-rw-r--r--arch/sparc64/kernel/process.c81
-rw-r--r--arch/sparc64/kernel/rtrap.S15
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/signal.c438
-rw-r--r--arch/sparc64/kernel/signal32.c19
-rw-r--r--arch/sparc64/kernel/sparcelf32.c1281
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c334
-rw-r--r--arch/sparc64/kernel/traps.c35
-rw-r--r--arch/sparc64/kernel/ttable.S28
-rw-r--r--arch/sparc64/kernel/winfixup.S101
-rw-r--r--arch/sparc64/lib/blockops.S66
-rw-r--r--arch/sparc64/lib/checksum.S25
-rw-r--r--arch/sparc64/lib/copy_from_user.S15
-rw-r--r--arch/sparc64/lib/copy_to_user.S15
-rw-r--r--arch/sparc64/lib/strlen_user.S12
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S4
-rw-r--r--arch/sparc64/mm/asyncd.c7
-rw-r--r--arch/sparc64/mm/fault.c23
-rw-r--r--arch/sparc64/mm/init.c44
195 files changed, 4970 insertions, 6074 deletions
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index a6ee5a17c..0c3c65d28 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -42,6 +42,13 @@ CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_EM86=y
+# CONFIG_PNP_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
#
# Floppy, IDE, and other block devices
@@ -72,9 +79,10 @@ CONFIG_BLK_DEV_RAM=y
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
CONFIG_INET=y
-# CONFIG_IP_FORWARD is not set
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
#
# (it is safe to leave these untouched)
@@ -133,11 +141,11 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
CONFIG_SCSI_QLOGIC_ISP=y
# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
@@ -155,19 +163,22 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
-# CONFIG_LAPBETHER is not set
# CONFIG_SLIP is not set
# CONFIG_TR is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
#
# ISDN subsystem
@@ -192,12 +203,16 @@ CONFIG_MSDOS_FS=y
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
#
@@ -206,12 +221,8 @@ CONFIG_ISO9660_FS=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
-# CONFIG_DIGI is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_STALDRV is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_ESPSERIAL is not set
-# CONFIG_PRINTER is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_MOUSE=y
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
@@ -224,7 +235,6 @@ CONFIG_PSMOUSE=y
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
-CONFIG_RTC_ARC=y
#
# Sound
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index ef582b80e..af26f8996 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -126,7 +126,8 @@
.ent entInt
entInt:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entInt
br $31,ret_from_sys_call
.end entInt
@@ -147,7 +148,8 @@ entMM:
stq $15,48($30)
addq $30,56,$19
/* handle the fault */
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_page_fault
/* reload the registers after the exception code played. */
ldq $9,0($30)
@@ -167,7 +169,8 @@ entMM:
.ent entArith
entArith:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
/* How much of a win is this clockwise? We are, after all, messing
up the call/return prefetch stack. -- rth */
lda $27,do_entArith
@@ -180,7 +183,8 @@ entArith:
.ent entIF
entIF:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
lda $27,do_entIF
lda $26,ret_from_sys_call
jsr $31,($27),do_entIF
@@ -221,12 +225,13 @@ kernel_clone:
.globl __kernel_thread
.ent __kernel_thread
__kernel_thread:
+ ldgp $29,0($27) /* we can be called from a module */
.frame $30, 4*8, $26
subq $30,4*8,$30
stq $10,16($30)
stq $9,8($30)
stq $26,0($30)
- .prologue 0
+ .prologue 1
bis $17,$17,$9 /* save fn */
bis $18,$18,$10 /* save arg */
bsr $26,kernel_clone
@@ -238,10 +243,9 @@ __kernel_thread:
ret $31,($26),1
/* this is in child: look out as we don't have any stack here.. */
1: bis $9,$9,$27 /* get fn */
- br $29,2f
-2: ldgp $29,0($29)
+ lda $8,0x3fff
bis $10,$10,$16 /* get arg */
- ldq $8,current_set
+ bic $30,$8,$8 /* get current */
jsr $26,($27)
bis $0,$0,$16
jsr $26,sys_exit
@@ -382,7 +386,8 @@ entUna:
stq $29,232($30)
stq $30,240($30)
stq $31,248($30)
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entUna
ldq $0,0($30)
ldq $1,8($30)
@@ -432,7 +437,8 @@ entUnaUser:
stq $14,40($30)
stq $15,48($30)
bis $31,$30,$19
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
jsr $26,do_entUnaUser
ldq $9,0($30)
ldq $10,8($30)
@@ -497,7 +503,8 @@ alpha_switch_to:
.ent entSys
entSys:
SAVE_ALL
- ldq $8,current_set
+ lda $8,0x3fff
+ bic $30,$8,$8
lda $4,NR_SYSCALLS($31)
stq $16,SP_OFF+24($30)
lda $5,sys_call_table
@@ -532,7 +539,7 @@ ret_from_handle_bh:
ret_from_reschedule:
lda $0,need_resched
ldl $2,0($0)
- lda $4,init_task
+ lda $4,init_task_union
bne $2,reschedule
xor $4,$8,$4
beq $4,restore_all
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 17ca4581a..f76213624 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -23,9 +23,11 @@ _stext:
__start:
br $27,1f
1: ldgp $29,0($27)
- /* We need to get current loaded up with our first task. */
- ldq $8,current_set
- /* And then we can start the kernel. */
+ /* We need to get current loaded up with our first task... */
+ lda $8,init_task_union
+ /* ... and find our stack ... */
+ lda $30,0x4000($8)
+ /* ... and then we can start the kernel. */
jsr $26,start_kernel
halt
.end __start
@@ -63,22 +65,6 @@ rdusp:
.end rdusp
.align 3
- .globl tbi
- .ent tbi
-tbi:
- call_pal PAL_tbi
- ret ($26)
- .end tbi
-
- .align 3
- .globl imb
- .ent imb
-imb:
- call_pal PAL_imb
- ret ($26)
- .end imb
-
- .align 3
.globl rdmces
.ent rdmces
rdmces:
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 2eb2d51b7..b6c97e726 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -37,6 +37,24 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+union task_union init_task_union __attribute__((section("init_task")))
+ = { task: INIT_TASK };
/*
* No need to acquire the kernel lock, we're entirely local..
@@ -186,7 +204,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
if (!(regs->ps & 8))
stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
- childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+ childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
*childregs = *regs;
childregs->r0 = 0;
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 019fb6b95..c388f0b51 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -67,7 +67,7 @@
* | | |
* | | v
* +================================+ <-------------------------
- * task->kernel_stack_page
+ * task + PAGE_SIZE
*/
#define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
@@ -107,19 +107,6 @@ static unsigned short regoff[] = {
static long zero;
-
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -133,7 +120,7 @@ static inline long get_reg(struct task_struct * task, long regno)
zero = 0;
addr = &zero;
} else {
- addr = (long *) (task->kernel_stack_page + regoff[regno]);
+ addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
}
return *addr;
}
@@ -150,7 +137,7 @@ static inline int put_reg(struct task_struct *task, long regno, long data)
} else if (regno == 31) {
addr = &zero;
} else {
- addr = (long *) (task->kernel_stack_page + regoff[regno]);
+ addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
}
*addr = data;
return 0;
@@ -174,7 +161,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -184,7 +171,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -194,7 +181,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -225,7 +212,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -235,7 +222,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -245,12 +232,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -507,7 +494,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
if (request == PTRACE_ATTACH) {
ret = -EPERM;
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 0fa1129ee..31a1f21fc 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -21,9 +21,9 @@
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
+#include <linux/ioport.h>
#ifdef CONFIG_RTC
-#include <linux/ioport.h>
#include <linux/timex.h>
#endif
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index a7b1e6f2c..a8bc34108 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -97,7 +97,7 @@ good_area:
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
}
- handle_mm_fault(vma, address, cause > 0);
+ handle_mm_fault(tsk, vma, address, cause > 0);
up(&mm->mmap_sem);
return;
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 13e8e4ce4..67faa97d4 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -133,7 +133,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
init_task.tss.ptbr = newptbr;
init_task.tss.pal_flags = 1; /* set FEN, clear everything else */
init_task.tss.flags = 0;
- init_task.kernel_stack_page = INIT_STACK;
load_PCB(&init_task.tss);
flush_tlb_all();
@@ -182,7 +181,7 @@ void free_initmem (void)
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
free_page(addr);
}
- printk ("Freeing unused kernel memory: %dk freed\n",
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(&__init_end - &__init_begin) >> 10);
}
diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds
index 2a5f00989..0fb2276ea 100644
--- a/arch/alpha/vmlinux.lds
+++ b/arch/alpha/vmlinux.lds
@@ -5,6 +5,7 @@ SECTIONS
. = 0xfffffc0000310000;
_text = .;
.text : { *(.text) }
+ .text2 : { *(.text2) }
_etext = .;
/* Exception table */
@@ -25,9 +26,12 @@ SECTIONS
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
- . = ALIGN(8192);
+ . = ALIGN(2*8192); /* Align double page for init_task_union */
__init_end = .;
+ /* The initial task and kernel stack */
+ init_task : { *(init_task) }
+
/* Global data */
_data = .;
.rodata : { *(.rodata) }
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index c67b8671a..bc4e03029 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -45,7 +45,7 @@ ifdef SMP
CFLAGS := $(CFLAGS) -D__SMP__
endif
-HEAD := arch/i386/kernel/head.o
+HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES)
@@ -85,7 +85,7 @@ bzdisk: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
install: vmlinux
- @$(MAKEBOOT) install
+ @$(MAKEBOOT) BOOTIMAGE=bzImage install
archclean:
@$(MAKEBOOT) clean
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 8507b7081..d09f11283 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -1,12 +1,13 @@
!
-! Display adapter & video mode setup, version 2.10 (11-Nov-96)
+! Display adapter & video mode setup, version 2.11 (03-May-97)
!
-! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
+! Copyright (C) 1995 -- 1997 Martin Mares <mj@k332.feld.cvut.cz>
! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
!
-! Enable autodetection of SVGA adapters and modes
-#define CONFIG_VIDEO_SVGA
+! Enable autodetection of SVGA adapters and modes. If you really need this
+! feature, drop me a mail as I think of removing it some day...
+#undef CONFIG_VIDEO_SVGA
! Enable autodetection of VESA modes
#define CONFIG_VIDEO_VESA
@@ -1807,11 +1808,11 @@ listhdr: db 0x0d, 0x0a
.ascii "Mode: COLSxROWS:"
crlft: db 0x0d, 0x0a, 0
prompt: db 0x0d, 0x0a
- .ascii "Enter mode number: "
+ .ascii "Enter mode number or `scan': "
db 0
unknt: .ascii "Unknown mode ID. Try again."
db 0
-badmdt: .ascii "You passed an undefined mode number to setup."
+badmdt: .ascii "You passed an undefined mode number."
db 0x0d, 0x0a, 0
vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
.ascii "report to <mj@k332.feld.cvut.cz>."
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index e5b5d9f84..a27b6ebce 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -141,6 +141,7 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index e04fb5efb..9491ef562 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -15,7 +15,7 @@ else
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
endif
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index e128000c3..157e62b2d 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -1,6 +1,8 @@
/*
* bios32.c - BIOS32, PCI BIOS functions.
*
+ * $Id: bios32.c,v 1.11 1997/05/07 13:35:21 mj Exp $
+ *
* Sponsored by
* iX Multiuser Multitasking Magazine
* Hannover, Germany
@@ -52,6 +54,11 @@
* Feb 3, 1997 : Set internal functions to static, save/restore flags
* avoid dead locks reading broken PCI BIOS, werner@suse.de
*
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ * (mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7, 1997 : Added some missing cli()'s. [mj]
+ *
*/
#include <linux/config.h>
@@ -158,7 +165,7 @@ static unsigned long bios32_service(unsigned long service)
unsigned long entry; /* %edx */
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)"
: "=a" (return_code),
"=b" (address),
@@ -173,10 +180,10 @@ static unsigned long bios32_service(unsigned long service)
case 0:
return address + entry;
case 0x80: /* Not present */
- printk("bios32_service(%ld) : not present\n", service);
+ printk("bios32_service(0x%lx) : not present\n", service);
return 0;
default: /* Shouldn't happen */
- printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n",
+ printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
service, return_code);
return 0;
}
@@ -189,7 +196,7 @@ static struct {
} pci_indirect = { 0, KERNEL_CS };
-__initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static int check_pcibios(void))
{
unsigned long signature;
unsigned char present_status;
@@ -201,7 +208,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
pci_indirect.address = pcibios_entry | PAGE_OFFSET;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -212,7 +219,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "bx", "cx");
- restore_flags(flags);
+ restore_flags(flags);
present_status = (pack >> 16) & 0xff;
major_revision = (pack >> 8) & 0xff;
@@ -232,9 +239,10 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign
if (pcibios_entry) {
printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
major_revision, minor_revision, pcibios_entry);
+ return 1;
}
}
- return memory_start;
+ return 0;
}
@@ -245,7 +253,7 @@ static int pci_bios_find_class (unsigned int class_code, unsigned short index,
unsigned long ret;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__ ("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -270,7 +278,7 @@ static int pci_bios_find_device (unsigned short vendor, unsigned short device_id
unsigned short ret;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -295,7 +303,7 @@ static int pci_bios_read_config_byte(unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -317,7 +325,7 @@ static int pci_bios_read_config_word (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -339,7 +347,7 @@ static int pci_bios_read_config_dword (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -361,7 +369,7 @@ static int pci_bios_write_config_byte (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -383,7 +391,7 @@ static int pci_bios_write_config_word (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -405,7 +413,7 @@ static int pci_bios_write_config_dword (unsigned char bus,
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
__asm__("lcall (%%esi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -476,7 +484,7 @@ static int pci_direct_find_class (unsigned int class_code, unsigned short index,
struct pci_dev *dev;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->class == class_code) {
if (curr == index) {
@@ -502,7 +510,7 @@ static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
switch (where & 3) {
case 0: *value = inb(0xCFC);
@@ -523,7 +531,7 @@ static int pci_conf1_read_config_word (unsigned char bus,
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
if (where & 2)
*value = inw(0xCFE);
@@ -538,7 +546,7 @@ static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inl(0xCFC);
restore_flags(flags);
@@ -550,7 +558,7 @@ static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outb(value, 0xCFC);
restore_flags(flags);
@@ -562,7 +570,7 @@ static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outw(value, 0xCFC);
restore_flags(flags);
@@ -574,7 +582,7 @@ static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outl(value, 0xCFC);
restore_flags(flags);
@@ -610,7 +618,7 @@ static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inb(IOADDR(device_fn,where));
@@ -626,7 +634,7 @@ static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_f
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inw(IOADDR(device_fn,where));
@@ -642,7 +650,7 @@ static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inl (IOADDR(device_fn,where));
@@ -656,7 +664,7 @@ static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outb (value, IOADDR(device_fn,where));
@@ -670,7 +678,7 @@ static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outw (value, IOADDR(device_fn,where));
@@ -684,7 +692,7 @@ static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device
{
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outl (value, IOADDR(device_fn,where));
@@ -716,7 +724,7 @@ __initfunc(static struct pci_access *check_direct_pci(void))
unsigned int tmp;
unsigned long flags;
- save_flags(flags);
+ save_flags(flags); cli();
/*
* check if configuration type 1 works
@@ -912,13 +920,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
bios32_entry = check->fields.entry;
printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
bios32_indirect.address = bios32_entry + PAGE_OFFSET;
- access_pci = &pci_bios_access;
}
}
}
- if (bios32_entry) {
- memory_start = check_pcibios (memory_start, memory_end);
- }
+ if (bios32_entry && check_pcibios())
+ access_pci = &pci_bios_access;
#endif
return memory_start;
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 84fe0c7fd..ac67da797 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -110,62 +110,45 @@ ENOSYS = 38
addl $4,%esp; \
iret
-#ifdef __SMP__
-/* Get the processor ID multiplied by 4 */
-#define GET_PROCESSOR_OFFSET(reg) \
- movl SYMBOL_NAME(apic_reg), reg; \
- movl 32(reg), reg; \
- shrl $22, reg; \
- andl $0x3C, reg;
-
-#define GET_CURRENT(reg) \
- GET_PROCESSOR_OFFSET(reg) \
- movl SYMBOL_NAME(current_set)(reg),reg
-
-#else
-
#define GET_CURRENT(reg) \
- movl SYMBOL_NAME(current_set),reg
-
-#endif
+ movl %esp, reg; \
+ andl $-8192, reg;
ENTRY(lcall7)
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
- GET_CURRENT(%ebx)
movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
movl CS(%esp),%edx # this is eip..
movl EFLAGS(%esp),%ecx # and this is cs..
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
- movl %esp,%eax
- GET_CURRENT(%edx)
- pushl %eax
- movl exec_domain(%edx),%edx # Get the execution domain
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
call *%edx
popl %eax
jmp ret_from_sys_call
+
#ifdef __SMP__
ALIGN
.globl ret_from_smpfork
ret_from_smpfork:
+ GET_CURRENT(%ebx)
btrl $0, SYMBOL_NAME(scheduler_lock)
jmp ret_from_sys_call
#endif /* __SMP__ */
- ALIGN
-handle_bottom_half:
- pushl $2f
- jmp SYMBOL_NAME(do_bottom_half)
-
- ALIGN
-reschedule:
- pushl $ret_from_sys_call
- jmp SYMBOL_NAME(schedule) # test
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
ENTRY(system_call)
pushl %eax # save orig_eax
@@ -180,16 +163,11 @@ ENTRY(system_call)
ALIGN
.globl ret_from_sys_call
.globl ret_from_intr
-ret_from_intr:
ret_from_sys_call:
- GET_CURRENT(%ebx)
movl SYMBOL_NAME(bh_mask),%eax
andl SYMBOL_NAME(bh_active),%eax
jne handle_bottom_half
-2: movl EFLAGS(%esp),%eax # mix EFLAGS and CS
- movb CS(%esp),%al
- testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
- je 1f
+ret_with_reschedule:
cmpl $0,SYMBOL_NAME(need_resched)
jne reschedule
movl blocked(%ebx),%eax
@@ -197,7 +175,6 @@ ret_from_sys_call:
notl %eax
andl signal(%ebx),%eax
jne signal_return
-1:
RESTORE_ALL
ALIGN
signal_return:
@@ -230,6 +207,30 @@ badsys:
movl $-ENOSYS,EAX(%esp)
jmp ret_from_sys_call
+ ALIGN
+ret_from_exception:
+ movl SYMBOL_NAME(bh_mask),%eax
+ andl SYMBOL_NAME(bh_active),%eax
+ jne handle_bottom_half
+ ALIGN
+ret_from_intr:
+ GET_CURRENT(%ebx)
+ movl EFLAGS(%esp),%eax # mix EFLAGS and CS
+ movb CS(%esp),%al
+ testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
+ jne ret_with_reschedule
+ RESTORE_ALL
+
+ ALIGN
+handle_bottom_half:
+ pushl $ret_from_intr
+ jmp SYMBOL_NAME(do_bottom_half)
+
+ ALIGN
+reschedule:
+ pushl $ret_from_sys_call
+ jmp SYMBOL_NAME(schedule) # test
+
ENTRY(divide_error)
pushl $0 # no error code
@@ -260,7 +261,7 @@ error_code:
GET_CURRENT(%ebx)
call *%ecx
addl $8,%esp
- jmp ret_from_sys_call
+ jmp ret_from_exception
ENTRY(coprocessor_error)
pushl $0
@@ -271,7 +272,7 @@ ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
GET_CURRENT(%ebx)
- pushl $ret_from_sys_call
+ pushl $ret_from_exception
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je SYMBOL_NAME(math_state_restore)
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 2bd095997..a42b87b1b 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -39,19 +39,21 @@ startup_32:
jz 1f
/*
* New page tables may be in 4Mbyte page mode and may
- * be using the global pages.
+ * be using the global pages.
+ *
+ * NOTE! We have to correct for the fact that we're
+ * not yet offset 0xC0000000..
*/
+#define cr4_bits mmu_cr4_features-0xC0000000
#ifdef GAS_KNOWS_CR4
movl %cr4,%eax # Turn on 4Mb pages
- orl $16+128,%eax
+ orl cr4_bits,%eax
movl %eax,%cr4
#else
.byte 0x0f,0x20,0xe0
- orl $16+128,%eax
+ orl cr4_bits,%eax
.byte 0x0f,0x22,0xe0
#endif
- movl %eax,%cr3 /* flush TLB as per app note */
- movl %cr0,%eax
#endif
/*
* Setup paging (the tables are already set up, just switch them on)
@@ -67,24 +69,16 @@ startup_32:
movl $1f,%eax
jmp *%eax /* make sure eip is relocated */
1:
+ /* Set up the stack pointer */
+ lss stack_start,%esp
#ifdef __SMP__
orw %bx,%bx
jz 1f /* Initial CPU cleans BSS */
-/*
- * Set up the stack
- */
- movl $(KERNEL_DS),%eax /* walken modif */
- mov %ax,%ss
- xorl %eax,%eax
- movw %cx, %ax
- movl %eax,%esp
- addl $0xC0000000, %esp /* shift it to the upper mapping */
pushl $0
popfl
jmp checkCPUtype
1:
- lss stack_start,%esp
#endif __SMP__
/*
* Clear BSS first so that there are no surprises...
@@ -305,15 +299,53 @@ rp_sidt:
jne rp_sidt
ret
+ENTRY(stack_start)
+ .long SYMBOL_NAME(init_task_union)+8192
+ .long KERNEL_DS
+
+/* This is the default interrupt "handler" :-) */
+int_msg:
+ .asciz "Unknown interrupt\n"
+ ALIGN
+ignore_int:
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ movl $(KERNEL_DS),%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ pushl $int_msg
+ call SYMBOL_NAME(printk)
+ popl %eax
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+/*
+ * The interrupt descriptor table has room for 256 idt's
+ */
+ ALIGN
+.word 0
+idt_descr:
+ .word 256*8-1 # idt contains 256 entries
+ .long SYMBOL_NAME(idt)
+
+ ALIGN
+.word 0
+gdt_descr:
+#ifdef CONFIG_APM
+ .word (11+2*NR_TASKS)*8-1
+#else
+ .word (8+2*NR_TASKS)*8-1
+#endif
+ .long SYMBOL_NAME(gdt)
/*
- * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x101000
- * with the introduction of the compressed boot code. Theoretically,
- * the original design of overlaying the startup code with the swapper
- * page directory is still possible --- it would reduce the size of the kernel
- * by 2-3k. This would be a good thing to do at some point.....
- *
* This is initialized to create a identity-mapping at 0-4M (for bootup
* purposes) and another mapping of the 0-4M area at virtual address
* 0xC0000000.
@@ -471,63 +503,29 @@ ENTRY(empty_bad_page_table)
ENTRY(empty_zero_page)
.org 0x6000
-
-stack_start:
- .long SYMBOL_NAME(init_user_stack)+4096
- .long KERNEL_DS
-
-/* This is the default interrupt "handler" :-) */
-int_msg:
- .asciz "Unknown interrupt\n"
- ALIGN
-ignore_int:
- cld
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $(KERNEL_DS),%eax
- mov %ax,%ds
- mov %ax,%es
- mov %ax,%fs
- pushl $int_msg
- call SYMBOL_NAME(printk)
- popl %eax
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
+ENTRY(this_must_match_init_task)
/*
- * The interrupt descriptor table has room for 256 idt's
+ * This starts the data section. Note that the above is all
+ * in the text section because it has alignment requirements
+ * that we cannot fulfill any other way.
*/
- ALIGN
-.word 0
-idt_descr:
- .word 256*8-1 # idt contains 256 entries
- .long SYMBOL_NAME(idt)
+.data
+ALIGN
+/* 256 quadwords - 2048 bytes of idt */
ENTRY(idt)
.fill 256,8,0 # idt is uninitialized
- ALIGN
-.word 0
-gdt_descr:
-#ifdef CONFIG_APM
- .word (11+2*NR_TASKS)*8-1
-#else
- .word (8+2*NR_TASKS)*8-1
-#endif
- .long SYMBOL_NAME(gdt)
-
/*
* This gdt setup gives the kernel a 1GB address space at virtual
* address 0xC0000000 - space enough for expansion, I hope.
+ *
+ * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
+ * gdt entries. Ugh.
+ *
+ * NOTE! Make sure the gdt descriptor in head.S matches this if you
+ * change anything.
*/
ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 8c16f0204..daa6baf42 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -19,6 +19,11 @@ extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(elf_fpregset_t *);
extern void __lock_kernel(void);
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
/* platform dependent support */
EXPORT_SYMBOL(EISA_bus);
EXPORT_SYMBOL(MCA_bus);
@@ -39,12 +44,13 @@ EXPORT_SYMBOL(csum_partial_copy);
#ifdef __SMP__
EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */
EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(active_kernel_processor);
+EXPORT_SYMBOL_NOVERS(kernel_flag);
+EXPORT_SYMBOL_NOVERS(active_kernel_processor);
EXPORT_SYMBOL(smp_invalidate_needed);
EXPORT_SYMBOL_NOVERS(__lock_kernel);
/* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
new file mode 100644
index 000000000..cc0a19231
--- /dev/null
+++ b/arch/i386/kernel/init_task.c
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 95a7b525f..e5fb5acb1 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -44,9 +44,6 @@ extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
#define CR0_NE 32
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
-
unsigned int local_irq_count[NR_CPUS];
#ifdef __SMP__
atomic_t __intel_bh_counter;
@@ -58,51 +55,84 @@ int __intel_bh_counter;
static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
#endif
-static inline void mask_irq(unsigned int irq_nr)
-{
- unsigned char mask;
+/*
+ * This contains the irq mask for both irq controllers
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21 (((char *)(&cached_irq_mask))[0])
+#define cached_A1 (((char *)(&cached_irq_mask))[1])
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8) {
- cache_21 |= mask;
- outb(cache_21,0x21);
+spinlock_t irq_controller_lock;
+
+/*
+ * This is always called from an interrupt context
+ * with local interrupts disabled. Don't worry about
+ * irq-safe locks.
+ *
+ * Note that we always ack the primary irq controller,
+ * even if the interrupt came from the secondary, as
+ * the primary will still have routed it. Oh, the joys
+ * of PC hardware.
+ */
+static inline void mask_and_ack_irq(int irq_nr)
+{
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ if (irq_nr & 8) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x20,0xA0);
} else {
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
}
+ outb(0x20,0x20);
+ spin_unlock(&irq_controller_lock);
}
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void set_irq_mask(int irq_nr)
{
- unsigned char mask;
-
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
+ if (irq_nr & 8) {
+ outb(cached_A1,0xA1);
} else {
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
+ outb(cached_21,0x21);
}
}
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= 1 << irq_nr;
+ set_irq_mask(irq_nr);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << irq_nr);
+ set_irq_mask(irq_nr);
+}
+
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&irq_controller_lock, flags);
mask_irq(irq_nr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+ synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
unmask_irq(irq_nr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
}
/*
@@ -133,7 +163,8 @@ void enable_irq(unsigned int irq_nr)
#error make irq stub building NR_IRQS dependent and remove me.
#endif
-BUILD_TIMER_IRQ(FIRST,0,0x01)
+BUILD_COMMON_IRQ()
+BUILD_IRQ(FIRST,0,0x01)
BUILD_IRQ(FIRST,1,0x02)
BUILD_IRQ(FIRST,2,0x04)
BUILD_IRQ(FIRST,3,0x08)
@@ -157,10 +188,6 @@ BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt)
#endif
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
static void (*interrupt[17])(void) = {
IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
@@ -168,28 +195,6 @@ static void (*interrupt[17])(void) = {
IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
};
-static void (*fast_interrupt[16])(void) = {
- fast_IRQ0_interrupt, fast_IRQ1_interrupt,
- fast_IRQ2_interrupt, fast_IRQ3_interrupt,
- fast_IRQ4_interrupt, fast_IRQ5_interrupt,
- fast_IRQ6_interrupt, fast_IRQ7_interrupt,
- fast_IRQ8_interrupt, fast_IRQ9_interrupt,
- fast_IRQ10_interrupt, fast_IRQ11_interrupt,
- fast_IRQ12_interrupt, fast_IRQ13_interrupt,
- fast_IRQ14_interrupt, fast_IRQ15_interrupt
-};
-
-static void (*bad_interrupt[16])(void) = {
- bad_IRQ0_interrupt, bad_IRQ1_interrupt,
- bad_IRQ2_interrupt, bad_IRQ3_interrupt,
- bad_IRQ4_interrupt, bad_IRQ5_interrupt,
- bad_IRQ6_interrupt, bad_IRQ7_interrupt,
- bad_IRQ8_interrupt, bad_IRQ9_interrupt,
- bad_IRQ10_interrupt, bad_IRQ11_interrupt,
- bad_IRQ12_interrupt, bad_IRQ13_interrupt,
- bad_IRQ14_interrupt, bad_IRQ15_interrupt
-};
-
/*
* Initial irq handlers.
*/
@@ -240,14 +245,10 @@ int get_irq_list(char *buf)
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %10u %c %s",
- i, kstat.interrupts[i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ len += sprintf(buf+len, "%2d: %10u %s",
+ i, kstat.interrupts[i], action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
+ len += sprintf(buf+len, ", %s", action->name);
}
len += sprintf(buf+len, "\n");
}
@@ -298,13 +299,9 @@ int get_smp_prof_list(char *buf) {
for (j=0;j<smp_num_cpus;j++)
len+=sprintf(buf+len, "%10d ",
int_count[cpu_logical_map[j]][i]);
- len += sprintf(buf+len, "%c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ len += sprintf(buf+len, " %s", action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
+ len += sprintf(buf+len, ", %s", action->name);
}
len += sprintf(buf+len, "\n");
}
@@ -393,16 +390,8 @@ static inline void check_smp_invalidate(int cpu)
static unsigned long previous_irqholder;
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
-
static inline void wait_on_irq(int cpu, unsigned long where)
{
- int stuck = INIT_STUCK;
int local_count = local_irq_count[cpu];
/* Are we the only one in an interrupt context? */
@@ -421,13 +410,12 @@ static inline void wait_on_irq(int cpu, unsigned long where)
* their things before trying to get the lock again.
*/
for (;;) {
- STUCK;
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (global_irq_lock)
continue;
- if (!set_bit(0,&global_irq_lock))
+ if (!test_and_set_bit(0,&global_irq_lock))
break;
}
atomic_add(local_count, &global_irq_count);
@@ -456,28 +444,18 @@ void synchronize_irq(void)
}
}
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
static inline void get_irqlock(int cpu, unsigned long where)
{
- int stuck = INIT_STUCK;
-
- if (set_bit(0,&global_irq_lock)) {
+ if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ((unsigned char) cpu == global_irq_holder)
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
do {
- STUCK;
check_smp_invalidate(cpu);
} while (test_bit(0,&global_irq_lock));
- } while (set_bit(0,&global_irq_lock));
+ } while (test_and_set_bit(0,&global_irq_lock));
}
/*
* Ok, we got the lock bit.
@@ -519,7 +497,8 @@ void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
- __global_sti();
+ release_irqlock(smp_processor_id());
+ __sti();
break;
case 1:
__global_cli();
@@ -533,56 +512,58 @@ void __global_restore_flags(unsigned long flags)
#endif
/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
*/
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(struct pt_regs regs)
{
+ int irq = regs.orig_eax & 0xff;
struct irqaction * action;
- int do_random, cpu = smp_processor_id();
+ int status, cpu;
+
+ /*
+ * mask and ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ */
+ mask_and_ack_irq(irq);
+ cpu = smp_processor_id();
irq_enter(cpu, irq);
kstat.interrupts[irq]++;
- /* slow interrupts run with interrupts enabled */
- __sti();
+ /* Return with this interrupt masked if no action */
+ status = 0;
action = *(irq + irq_action);
- do_random = 0;
- while (action) {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
+ if (action) {
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, &regs);
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+
+ __cli();
+ spin_lock(&irq_controller_lock);
+ unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
}
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- irq_exit(cpu, irq);
-}
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
- struct irqaction * action;
- int do_random, cpu = smp_processor_id();
-
- irq_enter(cpu, irq);
- kstat.interrupts[irq]++;
- action = *(irq + irq_action);
- do_random = 0;
- while (action) {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, NULL);
- action = action->next;
- }
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
irq_exit(cpu, irq);
+ /*
+ * This should be conditional: we should really get
+ * a return code from the irq handler to tell us
+ * whether the handler wants us to do software bottom
+ * half handling or not..
+ */
+ if (1) {
+ if (bh_active & bh_mask)
+ do_bottom_half();
+ }
}
int setup_x86_irq(int irq, struct irqaction * new)
@@ -597,10 +578,6 @@ int setup_x86_irq(int irq, struct irqaction * new)
if (!(old->flags & new->flags & SA_SHIRQ))
return -EBUSY;
- /* Can't share interrupts unless both are same type */
- if ((old->flags ^ new->flags) & SA_INTERRUPT)
- return -EBUSY;
-
/* add new interrupt at end of irq queue */
do {
p = &old->next;
@@ -617,11 +594,9 @@ int setup_x86_irq(int irq, struct irqaction * new)
*p = new;
if (!shared) {
- if (new->flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
- else
- set_intr_gate(0x20+irq,interrupt[irq]);
+ spin_lock(&irq_controller_lock);
unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
}
restore_flags(flags);
return 0;
@@ -676,10 +651,6 @@ void free_irq(unsigned int irq, void *dev_id)
save_flags(flags);
cli();
*p = action->next;
- if (!irq[irq_action]) {
- mask_irq(irq);
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
- }
restore_flags(flags);
kfree(action);
return;
@@ -689,7 +660,7 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
+ unsigned int i, irqs = 0;
unsigned long delay;
/* first, enable any unassigned irqs */
@@ -705,19 +676,17 @@ unsigned long probe_irq_on (void)
/* about 100ms delay */;
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- return irqs & ~irqmask;
+ return irqs & ~cached_irq_mask;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
+ unsigned int i;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
#ifdef DEBUG
- printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask);
+ printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, cached_irq_mask);
#endif
- irqs &= irqmask;
+ irqs &= cached_irq_mask;
if (!irqs)
return 0;
i = ffz(~irqs);
@@ -729,10 +698,6 @@ int probe_irq_off (unsigned long irqs)
__initfunc(void init_IRQ(void))
{
int i;
- static unsigned char smptrap=0;
- if(smptrap)
- return;
- smptrap=1;
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -740,7 +705,7 @@ __initfunc(void init_IRQ(void))
outb(LATCH >> 8 , 0x40); /* MSB */
for (i = 0; i < NR_IRQS ; i++)
- set_intr_gate(0x20+i,bad_interrupt[i]);
+ set_intr_gate(0x20+i,interrupt[i]);
#ifdef __SMP__
/*
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 3a349f20a..1f9e89399 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -33,7 +33,6 @@ static inline void irq_enter(int cpu, int irq)
static inline void irq_exit(int cpu, int irq)
{
- __cli();
hardirq_exit(cpu);
release_irqlock(cpu);
}
@@ -63,125 +62,12 @@ static inline void irq_exit(int cpu, int irq)
"mov %dx,%ds\n\t" \
"mov %dx,%es\n\t"
-/*
- * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
- * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
- * call the routines that do signal handling etc on return, and can have
- * more relaxed register-saving etc. They are also atomic, and are thus
- * suited for small, fast interrupts like the serial lines or the harddisk
- * drivers, which don't actually need signal handling etc.
- *
- * Also note that we actually save only those registers that are used in
- * C subroutines (%eax, %edx and %ecx), so if you do something weird,
- * you're on your own. The only segments that are saved (not counting the
- * automatic stack and code segment handling) are %ds and %es, and they
- * point to kernel space. No messing around with %fs here.
- */
-#define SAVE_MOST \
- "cld\n\t" \
- "push %es\n\t" \
- "push %ds\n\t" \
- "pushl %eax\n\t" \
- "pushl %edx\n\t" \
- "pushl %ecx\n\t" \
- "movl $" STR(KERNEL_DS) ",%edx\n\t" \
- "mov %dx,%ds\n\t" \
- "mov %dx,%es\n\t"
-
-#define RESTORE_MOST \
- "popl %ecx\n\t" \
- "popl %edx\n\t" \
- "popl %eax\n\t" \
- "pop %ds\n\t" \
- "pop %es\n\t" \
- "iret"
-
-/*
- * Some fast irq handlers might want to access saved registers (mostly
- * cs or flags)
- */
-
-struct fast_irq_regs {
- long ecx;
- long edx;
- long eax;
- int xds;
- int xes;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
-};
-
-/*
- * The "inb" instructions are not needed, but seem to change the timings
- * a bit - without them it seems that the harddisk driver won't work on
- * all hardware. Arghh.
- */
-#define ACK_FIRST(mask,nr) \
- "inb $0x21,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
- "outb %al,$0x21\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tmovb $0x20,%al\n\t" \
- "outb %al,$0x20\n\t"
-
-#define ACK_SECOND(mask,nr) \
- "inb $0xA1,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
- "outb %al,$0xA1\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tmovb $0x20,%al\n\t" \
- "outb %al,$0xA0\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\toutb %al,$0x20\n\t"
-
-#define UNBLK_FIRST(mask) \
- "inb $0x21,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
- "outb %al,$0x21\n\t"
-
-#define UNBLK_SECOND(mask) \
- "inb $0xA1,%al\n\t" \
- "jmp 1f\n" \
- "1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
- "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
- "outb %al,$0xA1\n\t"
-
#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
-#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
-
-#ifdef __SMP__
-
-#define GET_CURRENT \
- "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \
- "movl 32(%ebx), %ebx\n\t" \
- "shrl $22,%ebx\n\t" \
- "andl $0x3C,%ebx\n\t" \
- "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t"
-
-#else
#define GET_CURRENT \
- "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
-
-#endif
+ "movl %esp, %ebx\n\t" \
+ "andl $-8192, %ebx\n\t"
#ifdef __SMP__
@@ -205,66 +91,30 @@ __asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(x) ":\n\t" \
"pushl $-1\n\t" \
- SAVE_ALL \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
+ SAVE_ALL \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
- "addl $4,%esp\n\t" \
+ "addl $4,%esp\n\t" \
"jmp ret_from_intr\n");
#endif /* __SMP__ */
-#define BUILD_IRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
+#define BUILD_COMMON_IRQ() \
__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
- "pushl $-"#nr"-2\n\t" \
+ "\n" __ALIGN_STR"\n" \
+ "common_interrupt:\n\t" \
SAVE_ALL \
- ACK_##chip(mask,(nr&7)) \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
- "addl $8,%esp\n\t" \
- UNBLK_##chip(mask) \
- "jmp ret_from_intr\n" \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
- SAVE_MOST \
- ACK_##chip(mask,(nr&7)) \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
- "addl $4,%esp\n\t" \
- UNBLK_##chip(mask) \
- RESTORE_MOST \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
- SAVE_MOST \
- ACK_##chip(mask,(nr&7)) \
- RESTORE_MOST);
-
-#define BUILD_TIMER_IRQ(chip,nr,mask) \
+ "pushl $ret_from_intr\n\t" \
+ "jmp "SYMBOL_NAME_STR(do_IRQ));
+
+#define BUILD_IRQ(chip,nr,mask) \
asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
__asm__( \
"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
- "pushl $-"#nr"-2\n\t" \
- SAVE_ALL \
- ACK_##chip(mask,(nr&7)) \
- "movl %esp,%eax\n\t" \
- "pushl %eax\n\t" \
- "pushl $" #nr "\n\t" \
- "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
- "addl $8,%esp\n\t" \
- UNBLK_##chip(mask) \
- "jmp ret_from_intr\n");
+ "pushl $"#nr"-256\n\t" \
+ "jmp common_interrupt");
/*
* x86 profiling function, SMP safe. We might want to do this in
@@ -276,15 +126,14 @@ static inline void x86_do_profile (unsigned long eip)
extern int _stext;
eip -= (unsigned long) &_stext;
eip >>= prof_shift;
- if (eip < prof_len)
- atomic_inc((atomic_t *)&prof_buffer[eip]);
- else
/*
* Dont ignore out-of-bounds EIP values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/
- atomic_inc((atomic_t *)&prof_buffer[prof_len-1]);
+ if (eip > prof_len-1)
+ eip = prof_len-1;
+ atomic_inc((atomic_t *)&prof_buffer[eip]);
}
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index fe4723951..33842a21f 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -30,6 +30,7 @@
#include <linux/delay.h>
#include <linux/smp.h>
#include <linux/reboot.h>
+#include <linux/init.h>
#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
#include <linux/apm_bios.h>
#endif
@@ -149,7 +150,8 @@ int cpu_idle(void *unused)
current->priority = -100;
while(1)
{
- if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
+ if(cpu_data[smp_processor_id()].hlt_works_ok &&
+ !hlt_counter && !need_resched)
__asm("hlt");
/*
* tq_scheduler currently assumes we're running in a process
@@ -183,7 +185,7 @@ static long no_idt[2] = {0, 0};
static int reboot_mode = 0;
static int reboot_thru_bios = 0;
-void reboot_setup(char *str, int *ints)
+__initfunc(void reboot_setup(char *str, int *ints))
{
while(1) {
switch (*str) {
@@ -324,11 +326,14 @@ void machine_restart(char * __unused)
pg0 [0] = 7;
- /* Use `swapper_pg_dir' as our page directory. Don't bother with
- `SET_PAGE_DIR' because interrupts are disabled and we're rebooting.
- This instruction flushes the TLB. */
+ /*
+ * Use `swapper_pg_dir' as our page directory. We bother with
+ * `SET_PAGE_DIR' because although might be rebooting, but if we change
+ * the way we set root page dir in the future, then we wont break a
+ * seldom used feature ;)
+ */
- __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory");
+ SET_PAGE_DIR(current,swapper_pg_dir);
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to "Bypass memory test (also warm
@@ -473,6 +478,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
int i;
struct pt_regs * childregs;
+ p->tss.tr = _TSS(nr);
+ p->tss.ldt = _LDT(nr);
p->tss.es = KERNEL_DS;
p->tss.cs = KERNEL_CS;
p->tss.ss = KERNEL_DS;
@@ -480,9 +487,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
p->tss.fs = USER_DS;
p->tss.gs = USER_DS;
p->tss.ss0 = KERNEL_DS;
- p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
- p->tss.tr = _TSS(nr);
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p;
+ childregs = ((struct pt_regs *) (p->tss.esp0)) - 1;
p->tss.esp = (unsigned long) childregs;
#ifdef __SMP__
p->tss.eip = (unsigned long) ret_from_smpfork;
@@ -496,7 +502,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
childregs->eax = 0;
childregs->esp = esp;
p->tss.back_link = 0;
- p->tss.ldt = _LDT(nr);
if (p->ldt) {
p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
if (p->ldt != NULL)
@@ -512,6 +517,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+
return 0;
}
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 920d1bc1c..0dfffd672 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -34,18 +34,6 @@
*/
#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the TSS.
@@ -95,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -105,7 +93,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -115,7 +103,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -146,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -156,7 +144,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -166,12 +154,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -381,7 +369,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index ec5954771..f62744d11 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -247,7 +247,7 @@ static const char * i586model(unsigned int nr)
static const char * i686model(unsigned int nr)
{
static const char *model[] = {
- "PPro A-step", "Pentium Pro"
+ "PPro A-step", "Pentium Pro", "2", "Pentium II"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
@@ -279,9 +279,10 @@ static const char * getmodel(int x86, int model)
int get_cpuinfo(char * buffer)
{
int i, len = 0;
+ int sep_bug;
static const char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov",
+ "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
"16", "17", "18", "19", "20", "21", "22", "mmx",
"24", "25", "26", "27", "28", "29", "30", "31"
};
@@ -321,10 +322,18 @@ int get_cpuinfo(char * buffer)
else
len += sprintf(buffer+len,
"stepping\t: unknown\n");
+
+ sep_bug = CD(have_cpuid) &&
+ (CD(x86_capability) & 0x800) &&
+ !memcmp(x86_vendor_id, "GenuineIntel", 12) &&
+ CD(x86) == 6 &&
+ CD(x86_model) < 3 &&
+ CD(x86_mask) < 3;
len += sprintf(buffer+len,
"fdiv_bug\t: %s\n"
"hlt_bug\t\t: %s\n"
+ "sep_bug\t\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid\t\t: %s\n"
@@ -332,6 +341,7 @@ int get_cpuinfo(char * buffer)
"flags\t\t:",
CD(fdiv_bug) ? "yes" : "no",
CD(hlt_works_ok) ? "no" : "yes",
+ sep_bug ? "yes" : "no",
CD(hard_math) ? "yes" : "no",
(CD(hard_math) && ignore_irq13)
? "yes" : "no",
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 970c8c5d7..3141c5318 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -318,6 +318,14 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
unsigned long signr;
struct sigaction * sa;
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if ((regs->xcs & 3) != 3)
+ return 1;
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
/*
@@ -384,10 +392,12 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
spin_lock_irq(&current->sigmask_lock);
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index a1590f500..1dc615501 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -1,5 +1,5 @@
/*
- * Intel MP v1.1/v1.4 specification support routines for multi-pentium
+ * Intel MP v1.1/v1.4 specification support routines for multi-pentium
* hosts.
*
* (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
@@ -46,14 +46,15 @@
#include <asm/smp.h>
#include <asm/io.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
#include "irq.h"
extern unsigned long start_kernel, _etext;
extern void update_one_process( struct task_struct *p,
- unsigned long ticks, unsigned long user,
- unsigned long system);
-void setup_APIC_clock (void);
-
+ unsigned long ticks, unsigned long user,
+ unsigned long system);
/*
* Some notes on processor bugs:
*
@@ -67,7 +68,7 @@ void setup_APIC_clock (void);
* Pentium
* There is a marginal case where REP MOVS on 100MHz SMP
* machines with B stepping processors can fail. XXX should provide
- * an L1cache=Writethrough or L1cache=off option.
+ * an L1cache=Writethrough or L1cache=off option.
*
* B stepping CPU's may hang. There are hardware work arounds
* for this. We warn about it in case your board doesnt have the work
@@ -91,12 +92,12 @@ void setup_APIC_clock (void);
* If this sounds worrying believe me these bugs are ___RARE___ and
* there's about nothing of note with C stepping upwards.
*/
-
-
+
+
/*
* Why isn't this somewhere standard ??
*/
-
+
extern __inline int max(int a,int b)
{
if(a>b)
@@ -121,7 +122,6 @@ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters
static unsigned int num_processors = 1; /* Internal processor count */
static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */
unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
-static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */
static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
int apic_version[NR_CPUS]; /* APIC version number */
static volatile int smp_commenced=0; /* Tripped when we start scheduling */
@@ -129,7 +129,6 @@ unsigned long apic_addr = 0xFEE00000; /* Address of APIC (defaults to 0xFEE000
unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */
unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC */
unsigned long apic_retval; /* Just debugging the assembler.. */
-unsigned char *kernel_stacks[NR_CPUS]; /* Kernel stack pointers for CPU's (debugging) */
static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */
@@ -195,10 +194,10 @@ static inline void ack_APIC_irq (void)
apic_write(APIC_EOI, 0);
}
-/*
+/*
* Checksum an MP configuration block.
*/
-
+
static int mpf_checksum(unsigned char *mp, int len)
{
int sum=0;
@@ -210,7 +209,7 @@ static int mpf_checksum(unsigned char *mp, int len)
/*
* Processor encoding in an MP configuration block
*/
-
+
static char *mpc_family(int family,int model)
{
static char n[32];
@@ -274,11 +273,11 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
/* set the local APIC address */
apic_addr = (unsigned long)phys_to_virt((unsigned long)mpc->mpc_lapic);
-
+
/*
* Now process the configuration blocks.
*/
-
+
while(count<mpc->mpc_length)
{
switch(*mpt)
@@ -290,13 +289,13 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
if(m->mpc_cpuflag&CPU_ENABLED)
{
printk("Processor #%d %s APIC version %d\n",
- m->mpc_apicid,
+ m->mpc_apicid,
mpc_family((m->mpc_cpufeature&
CPU_FAMILY_MASK)>>8,
(m->mpc_cpufeature&
CPU_MODEL_MASK)>>4),
m->mpc_apicver);
-#ifdef SMP_DEBUG
+#ifdef SMP_DEBUG
if(m->mpc_featureflag&(1<<0))
printk(" Floating point unit present.\n");
if(m->mpc_featureflag&(1<<7))
@@ -305,7 +304,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
printk(" 64 bit compare & exchange supported.\n");
if(m->mpc_featureflag&(1<<9))
printk(" Internal APIC present.\n");
-#endif
+#endif
if(m->mpc_cpuflag&CPU_BOOTPROCESSOR)
{
SMP_PRINTK((" Bootup CPU\n"));
@@ -313,10 +312,10 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
}
else /* Boot CPU already counted */
num_processors++;
-
+
if(m->mpc_apicid>NR_CPUS)
printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
- else
+ else
{
cpu_present_map|=(1<<m->mpc_apicid);
apic_version[m->mpc_apicid]=m->mpc_apicver;
@@ -337,7 +336,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
str));
mpt+=sizeof(*m);
count+=sizeof(*m);
- break;
+ break;
}
case MP_IOAPIC:
{
@@ -346,20 +345,20 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
if(m->mpc_flags&MPC_APIC_USABLE)
{
apics++;
- printk("I/O APIC #%d Version %d at 0x%lX.\n",
- m->mpc_apicid,m->mpc_apicver,
- m->mpc_apicaddr);
- io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
- }
- mpt+=sizeof(*m);
- count+=sizeof(*m);
- break;
+ printk("I/O APIC #%d Version %d at 0x%lX.\n",
+ m->mpc_apicid,m->mpc_apicver,
+ m->mpc_apicaddr);
+ io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
+ }
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
}
case MP_INTSRC:
{
struct mpc_config_intsrc *m=
(struct mpc_config_intsrc *)mpt;
-
+
mpt+=sizeof(*m);
count+=sizeof(*m);
break;
@@ -376,29 +375,29 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
}
if(apics>1)
printk("Warning: Multiple APIC's not supported.\n");
- return num_processors;
+ return num_processors;
}
/*
* Scan the memory blocks for an SMP configuration block.
*/
-
+
__initfunc(int smp_scan_config(unsigned long base, unsigned long length))
{
unsigned long *bp=phys_to_virt(base);
struct intel_mp_floating *mpf;
-
+
SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
bp,length));
if(sizeof(*mpf)!=16)
printk("Error: MPF size\n");
-
+
while(length>0)
{
if(*bp==SMP_MAGIC_IDENT)
{
mpf=(struct intel_mp_floating *)bp;
- if(mpf->mpf_length==1 &&
+ if(mpf->mpf_length==1 &&
!mpf_checksum((unsigned char *)bp,16) &&
(mpf->mpf_specification == 1
|| mpf->mpf_specification == 4) )
@@ -433,7 +432,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
* We know that page 0 is not
* used. Steal it for now!
*/
-
+
cfg=pg0[0];
pg0[0] = (apic_addr | 7);
local_flush_tlb();
@@ -451,7 +450,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
*
* END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK
*
- */
+ */
/*
* 2 CPUs, numbered 0 & 1.
*/
@@ -513,6 +512,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */
cpu_logical_map[0] = boot_cpu_id;
global_irq_holder = boot_cpu_id;
+ current->processor = boot_cpu_id;
printk("Processors: %d\n", num_processors);
/*
@@ -534,61 +534,37 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
extern unsigned char trampoline_data [];
extern unsigned char trampoline_end [];
+static unsigned char *trampoline_base;
/*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
* has made sure it's suitably aligned.
*/
-
-__initfunc(static void install_trampoline(unsigned char *mp))
+
+__initfunc(static unsigned long setup_trampoline(void))
{
- memcpy(mp, trampoline_data, trampoline_end - trampoline_data);
+ memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+ return virt_to_phys(trampoline_base);
}
/*
- * We are called very early to get the low memory for the trampoline/kernel stacks
- * This has to be done by mm/init.c to parcel us out nice low memory. We allocate
- * the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and
- * other things).
+ * We are called very early to get the low memory for the
+ * SMP bootup trampoline page.
*/
-
__initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
{
- int size=(num_processors-1)*PAGE_SIZE; /* Number of stacks needed */
-
- /*
- * Our stacks have to be below the 1Mb line, and mem_base on entry
- * is 4K aligned.
- */
-
- if(virt_to_phys((void *)(mem_base+size))>=0x9F000)
- panic("smp_alloc_memory: Insufficient low memory for kernel stacks 0x%lx.\n", mem_base);
- kstack_base=(void *)mem_base;
- mem_base+=size;
- kstack_end=(void *)mem_base;
- return mem_base;
-}
-
-/*
- * Hand out stacks one at a time.
- */
-
-__initfunc(static void *get_kernel_stack(void))
-{
- void *stack=kstack_base;
- if(kstack_base>=kstack_end)
- return NULL;
- kstack_base+=PAGE_SIZE;
- return stack;
+ if (virt_to_phys((void *)mem_base) >= 0x9F000)
+ panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base);
+ trampoline_base = (void *)mem_base;
+ return mem_base + PAGE_SIZE;
}
-
/*
* The bootstrap kernel entry code has set these up. Save them for
* a given CPU
*/
-
+
__initfunc(void smp_store_cpu_info(int id))
{
struct cpuinfo_x86 *c=&cpu_data[id];
@@ -615,7 +591,7 @@ __initfunc(void smp_store_cpu_info(int id))
* fired off. This allows the BP to have everything in order [we hope].
* At the end of this all the AP's will hit the system scheduling and off
* we go. Each AP will load the system gdt's and jump through the kernel
- * init into idle(). At this point the scheduler will one day take over
+ * init into idle(). At this point the scheduler will one day take over
* and give them jobs to do. smp_callin is a standard routine
* we use to track CPU's as they power up.
*/
@@ -634,74 +610,276 @@ __initfunc(void smp_callin(void))
extern void calibrate_delay(void);
int cpuid=GET_APIC_ID(apic_read(APIC_ID));
unsigned long l;
-
+
/*
* Activate our APIC
*/
-
- SMP_PRINTK(("CALLIN %d\n",smp_processor_id()));
+
+ SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
l=apic_read(APIC_SPIV);
l|=(1<<8); /* Enable */
apic_write(APIC_SPIV,l);
/*
- * Set up our APIC timer.
+ * Set up our APIC timer.
*/
setup_APIC_clock ();
sti();
/*
* Get our bogomips.
- */
+ */
calibrate_delay();
SMP_PRINTK(("Stack at about %p\n",&cpuid));
-
+
/*
* Save our processor parameters
*/
smp_store_cpu_info(cpuid);
+
/*
* Allow the master to continue.
- */
+ */
set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+}
+
+static int cpucount = 0;
+
+extern int cpu_idle(void * unused);
+
+/*
+ * Activate a secondary processor.
+ */
+__initfunc(int start_secondary(void *unused))
+{
+ smp_callin();
+ while (!smp_commenced)
+ barrier();
+ return cpu_idle(NULL);
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPU's - they just need to reload everything
+ * from the task structure
+ */
+__initfunc(void initialize_secondary(void))
+{
+ struct thread_struct * p = &current->tss;
+
/*
- * Until we are ready for SMP scheduling
+ * We don't actually need to load the full TSS,
+ * basically just the stack pointer and the eip.
*/
- load_ldt(0);
- local_flush_tlb();
-
- while (cpu_number_map[cpuid] == -1)
- barrier();
+ asm volatile("lldt %%ax": :"a" (p->ldt));
+ asm volatile("ltr %%ax": :"a" (p->tr));
+ asm volatile(
+ "movl %0,%%esp\n\t"
+ "jmp *%1"
+ :
+ :"r" (p->esp),"r" (p->eip));
+}
- while(!task[cpuid] || current_set[cpuid] != task[cpu_number_map[cpuid]])
- barrier();
+extern struct {
+ void * esp;
+ unsigned short ss;
+} stack_start;
- local_flush_tlb();
- load_TR(cpu_number_map[cpuid]);
+__initfunc(static void do_boot_cpu(int i))
+{
+ unsigned long cfg;
+ pgd_t maincfg;
+ struct task_struct *idle;
+ unsigned long send_status, accept_status;
+ int timeout, num_starts, j;
+ unsigned long start_eip;
- while(!smp_commenced)
- barrier();
-
+ /*
+ * We need an idle process for each processor.
+ */
+
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+ cpucount++;
+
+ idle = task[cpucount];
+ if (!idle)
+ panic("No idle process for CPU %d\n", i);
+
+ idle->processor = i;
+ cpu_logical_map[cpucount] = i;
+ cpu_number_map[i] = cpucount;
+
+ /* start_eip had better be page-aligned! */
+ start_eip = setup_trampoline();
+
+ printk("Booting processor %d eip %lx: ", i, start_eip); /* So we see what's up */
+ stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
+
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+ */
+
+ SMP_PRINTK(("Setting warm reset code and vector.\n"));
+
+ CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
+ SMP_PRINTK(("1.\n"));
+ *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
+ SMP_PRINTK(("2.\n"));
+ *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
+ SMP_PRINTK(("3.\n"));
+
+ maincfg=swapper_pg_dir[0];
+ ((unsigned long *)swapper_pg_dir)[0]=0x102007;
+
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ {
+ apic_write(APIC_ESR, 0);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+
+ /*
+ * Status is now clean
+ */
- SMP_PRINTK(("Commenced..\n"));
+ send_status = 0;
+ accept_status = 0;
+
+ /*
+ * Starting actual IPI sequence...
+ */
+
+ SMP_PRINTK(("Asserting INIT.\n"));
+
+ /*
+ * Turn INIT on
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ udelay(200);
+ SMP_PRINTK(("Deasserting INIT.\n"));
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ /*
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't
+ * send the STARTUP IPIs.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ num_starts = 2;
+ else
+ num_starts = 0;
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+
+ for (j = 1; !(send_status || accept_status)
+ && (j <= num_starts) ; j++)
+ {
+ SMP_PRINTK(("Sending STARTUP #%d.\n",j));
+ apic_write(APIC_ESR, 0);
+ SMP_PRINTK(("After apic_write.\n"));
+
+ /*
+ * STARTUP IPI
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD
+ | APIC_DEST_DM_STARTUP
+ | (start_eip >> 12)); /* Boot on the stack */
+ SMP_PRINTK(("Before start apic_write.\n"));
+ apic_write(APIC_ICR, cfg); /* Kick the second */
+
+ SMP_PRINTK(("Startup point 1.\n"));
+ timeout = 0;
+ do {
+ SMP_PRINTK(("Sleeping.\n")); udelay(1000000);
+ udelay(10);
+ } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
+ && (timeout++ < 1000));
+ udelay(200);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+ SMP_PRINTK(("After Startup.\n"));
+
+ if (send_status) /* APIC never delivered?? */
+ printk("APIC never delivered???\n");
+ if (accept_status) /* Send accept error */
+ printk("APIC delivery error (%lx).\n", accept_status);
+
+ if( !(send_status || accept_status) )
+ {
+ for(timeout=0;timeout<50000;timeout++)
+ {
+ if(cpu_callin_map[0]&(1<<i))
+ break; /* It has booted */
+ udelay(100); /* Wait 5s total for a response */
+ }
+ if(cpu_callin_map[0]&(1<<i))
+ {
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+#if 0
+ cpu_number_map[i] = cpucount;
+ cpu_logical_map[cpucount] = i;
+#endif
+ }
+ else
+ {
+ if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
+ printk("Stuck ??\n");
+ else
+ printk("Not responding.\n");
+ }
+ }
+ SMP_PRINTK(("CPU has booted.\n"));
+
+ swapper_pg_dir[0]=maincfg;
local_flush_tlb();
- sti();
+
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)phys_to_virt(8192)) = 0;
}
+
/*
* Cycle through the processors sending APIC IPI's to boot each.
*/
-
+
__initfunc(void smp_boot_cpus(void))
{
int i;
- int cpucount=0;
unsigned long cfg;
- pgd_t maincfg;
- void *stack;
- extern unsigned long init_user_stack[];
-
+
/*
* Initialize the logical to physical cpu number mapping
*/
@@ -712,12 +890,10 @@ __initfunc(void smp_boot_cpus(void))
/*
* Setup boot CPU information
*/
-
- kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */
smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
- cpu_present_map |= (1 << smp_processor_id());
+ cpu_present_map |= (1 << hard_smp_processor_id());
cpu_number_map[boot_cpu_id] = 0;
active_kernel_processor=boot_cpu_id;
@@ -744,11 +920,11 @@ __initfunc(void smp_boot_cpus(void))
*/
apic_reg = ioremap(apic_addr,4096);
-
+
if(apic_reg == NULL)
panic("Unable to map local apic.\n");
-
-#ifdef SMP_DEBUG
+
+#ifdef SMP_DEBUG
{
int reg;
@@ -785,11 +961,11 @@ __initfunc(void smp_boot_cpus(void))
SMP_PRINTK(("Getting LVT1: %x\n", reg));
}
#endif
-
+
/*
* Enable the local APIC
*/
-
+
cfg=apic_read(APIC_SPIV);
cfg|=(1<<8); /* Enable APIC */
apic_write(APIC_SPIV,cfg);
@@ -798,15 +974,15 @@ __initfunc(void smp_boot_cpus(void))
/*
* Set up our local APIC timer:
- */
+ */
setup_APIC_clock ();
/*
* Now scan the cpu present map and fire up the other CPUs.
*/
-
+
SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
-
+
for(i=0;i<NR_CPUS;i++)
{
/*
@@ -814,213 +990,17 @@ __initfunc(void smp_boot_cpus(void))
*/
if (i == boot_cpu_id)
continue;
-
+
if ((cpu_present_map & (1 << i))
&& (max_cpus < 0 || max_cpus > cpucount+1))
{
- unsigned long send_status, accept_status;
- int timeout, num_starts, j;
-
- /*
- * We need a kernel stack for each processor.
- */
-
- stack=get_kernel_stack(); /* We allocated these earlier */
- if(stack==NULL)
- panic("No memory for processor stacks.\n");
-
- kernel_stacks[i]=(void *)phys_to_virt((unsigned long)stack);
- install_trampoline(stack);
-
- printk("Booting processor %d stack %p: ",i,stack); /* So we set what's up */
-
- /*
- * This grunge runs the startup process for
- * the targeted processor.
- */
-
- SMP_PRINTK(("Setting warm reset code and vector.\n"));
-
- /*
- * Install a writable page 0 entry.
- */
-
- cfg=pg0[0];
-
- CMOS_WRITE(0xa, 0xf);
- pg0[0]=7;
- local_flush_tlb();
- SMP_PRINTK(("1.\n"));
- *((volatile unsigned short *) phys_to_virt(0x469)) = ((unsigned long)stack)>>4;
- SMP_PRINTK(("2.\n"));
- *((volatile unsigned short *) phys_to_virt(0x467)) = 0;
- SMP_PRINTK(("3.\n"));
-
- /*
- * Protect it again
- */
-
- pg0[0]= cfg;
- local_flush_tlb();
-
- /* walken modif
- * enable mapping of the first 4M at virtual
- * address zero
- */
-
- maincfg=swapper_pg_dir[0];
- ((unsigned long *)swapper_pg_dir)[0]=0x102007;
-
- /* no need to local_flush_tlb :
- we are setting this up for the slave processor ! */
-
- /*
- * Be paranoid about clearing APIC errors.
- */
-
- if ( apic_version[i] & 0xF0 )
- {
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
-
- /*
- * Status is now clean
- */
-
- send_status = 0;
- accept_status = 0;
-
- /*
- * Starting actual IPI sequence...
- */
-
- SMP_PRINTK(("Asserting INIT.\n"));
-
- /*
- * Turn INIT on
- */
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
- apic_write(APIC_ICR, cfg); /* Send IPI */
-
- udelay(200);
- SMP_PRINTK(("Deasserting INIT.\n"));
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_DM_INIT);
- apic_write(APIC_ICR, cfg); /* Send IPI */
-
- /*
- * Should we send STARTUP IPIs ?
- *
- * Determine this based on the APIC version.
- * If we don't have an integrated APIC, don't
- * send the STARTUP IPIs.
- */
-
- if ( apic_version[i] & 0xF0 )
- num_starts = 2;
- else
- num_starts = 0;
-
- /*
- * Run STARTUP IPI loop.
- */
-
- for (j = 1; !(send_status || accept_status)
- && (j <= num_starts) ; j++)
- {
- SMP_PRINTK(("Sending STARTUP #%d.\n",j));
-
- apic_write(APIC_ESR, 0);
- SMP_PRINTK(("After apic_write.\n"));
-
- /*
- * STARTUP IPI
- */
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD
- | APIC_DEST_DM_STARTUP
- | (((int)virt_to_phys(stack)) >> 12)); /* Boot on the stack */
- SMP_PRINTK(("Before start apic_write.\n"));
- apic_write(APIC_ICR, cfg); /* Kick the second */
-
- SMP_PRINTK(("Startup point 1.\n"));
- timeout = 0;
- do {
- SMP_PRINTK(("Sleeping.\n")); udelay(1000000);
- udelay(10);
- } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
- && (timeout++ < 1000));
- udelay(200);
-
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
- SMP_PRINTK(("After Startup.\n"));
-
- if (send_status) /* APIC never delivered?? */
- printk("APIC never delivered???\n");
- if (accept_status) /* Send accept error */
- printk("APIC delivery error (%lx).\n", accept_status);
-
- if( !(send_status || accept_status) )
- {
- for(timeout=0;timeout<50000;timeout++)
- {
- if(cpu_callin_map[0]&(1<<i))
- break; /* It has booted */
- udelay(100); /* Wait 5s total for a response */
- }
- if(cpu_callin_map[0]&(1<<i))
- {
- cpucount++;
- /* number CPUs logically, starting from 1 (BSP is 0) */
- cpu_number_map[i] = cpucount;
- cpu_logical_map[cpucount] = i;
- }
- else
- {
- if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
- printk("Stuck ??\n");
- else
- printk("Not responding.\n");
- }
- }
- SMP_PRINTK(("CPU has booted.\n"));
-
- /* walken modif
- * restore mapping of the first 4M
- */
-
- swapper_pg_dir[0]=maincfg;
-
- local_flush_tlb();
-
- /* mark "stuck" area as not stuck */
- *((volatile unsigned long *)phys_to_virt(8192)) = 0;
+ do_boot_cpu(i);
}
-
- /*
+
+ /*
* Make sure we unmap all failed CPUs
*/
-
+
if (cpu_number_map[i] == -1)
cpu_present_map &= ~(1 << i);
}
@@ -1056,12 +1036,12 @@ __initfunc(void smp_boot_cpus(void))
/*
* Allow the user to impress friends.
*/
-
+
SMP_PRINTK(("Before bogomips.\n"));
if(cpucount==0)
{
printk("Error: only one processor found.\n");
- cpu_present_map=(1<<smp_processor_id());
+ cpu_present_map=(1<<hard_smp_processor_id());
}
else
{
@@ -1071,8 +1051,8 @@ __initfunc(void smp_boot_cpus(void))
if(cpu_present_map&(1<<i))
bogosum+=cpu_data[i].udelay_val;
}
- printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
- cpucount+1,
+ printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+ cpucount+1,
(bogosum+2500)/500000,
((bogosum+2500)/5000)%100);
SMP_PRINTK(("Before bogocount - setting activated=1.\n"));
@@ -1096,7 +1076,7 @@ __initfunc(void smp_boot_cpus(void))
* IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That
* will also boost performance.
*/
-
+
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
unsigned long flags;
@@ -1109,11 +1089,11 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
/*
* During boot up send no messages
*/
-
+
if(!smp_activated || !smp_commenced)
return;
-
-
+
+
/*
* Skip the reschedule if we are waiting to clear a
* message at this time. The reschedule cannot wait
@@ -1121,7 +1101,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
*/
switch (msg) {
- case MSG_RESCHEDULE:
+ case MSG_RESCHEDULE:
irq = 0x30;
if (smp_cpu_in_msg[p])
return;
@@ -1148,21 +1128,21 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
* no data and can occur during a flush.. guess what panic
* I got to notice this bug...
*/
-
+
/*
* We are busy
*/
-
- smp_cpu_in_msg[p]++;
+ smp_cpu_in_msg[p]++;
+
/* printk("SMP message pass #%d to %d of %d\n",
p, msg, target);*/
-
+
/*
* Wait for the APIC to become ready - this should never occur. Its
* a debugging check really.
*/
-
+
while(ct<1000)
{
cfg=apic_read(APIC_ICR);
@@ -1171,14 +1151,14 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
ct++;
udelay(10);
}
-
+
/*
* Just pray... there is nothing more we can do
*/
-
+
if(ct==1000)
printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
-
+
/*
* Program the APIC to deliver the IPI
*/
@@ -1190,12 +1170,12 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xFDFFF; /* Clear bits */
- cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
+ cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
/*
* Set the target requirement
*/
-
+
if(target==MSG_ALL_BUT_SELF)
{
cfg|=APIC_DEST_ALLBUT;
@@ -1213,18 +1193,18 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
target_map=(1<<target);
cpu_callin_map[0]=0;
}
-
+
/*
* Send the IPI. The write to APIC_ICR fires this off.
*/
-
+
apic_write(APIC_ICR, cfg);
__restore_flags(flags);
-
+
/*
* Spin waiting for completion
*/
-
+
switch(wait)
{
int stuck;
@@ -1247,17 +1227,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
clear_bit(p, &smp_invalidate_needed);
--stuck;
if (!stuck) {
- printk("stuck on smp_invalidate_needed IPI wait\n");
+ printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p);
break;
}
}
break;
}
-
+
/*
* Record our completion
*/
-
+
smp_cpu_in_msg[p]--;
}
@@ -1266,14 +1246,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
* even with IRQ's off. We have to avoid a pair of crossing flushes
* or we are doomed. See the notes about smp_message_pass.
*/
-
+
void smp_flush_tlb(void)
{
unsigned long flags;
+
+#if 0
if(smp_activated && smp_processor_id()!=active_kernel_processor) {
printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
*(char *)0=0;
}
+#endif
/* printk("SMI-");*/
/*
@@ -1282,30 +1265,30 @@ void smp_flush_tlb(void)
* may issue a tlb flush. If you break any one of those three change this to an atomic
* bus locked or.
*/
-
+
smp_invalidate_needed=cpu_present_map;
-
+
/*
* Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
* ensure they don't do a spurious flush tlb or miss one.
*/
-
+
__save_flags(flags);
__cli();
smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
-
+
/*
* Flush the local TLB
*/
-
- local_flush_tlb();
+ local_flush_tlb();
+
__restore_flags(flags);
-
+
/*
* Completed.
*/
-
+
/* printk("SMID\n");*/
}
@@ -1315,14 +1298,14 @@ void smp_flush_tlb(void)
*
* We do profiling in every local tick, statistics/rescheduling
* happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing a 4 bytes multiplier
+ * multiplier is 1 and it can be changed by writing the new multiplier
* value into /proc/profile.
*/
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-static inline void smp_local_timer_interrupt(struct pt_regs * regs)
+void smp_local_timer_interrupt(struct pt_regs * regs)
{
int cpu = smp_processor_id();
@@ -1367,7 +1350,7 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
kstat.cpu_user += user;
kstat.cpu_system += system;
-
+
} else {
#ifdef __SMP_PROF__
if (test_bit(cpu,&smp_idle_map))
@@ -1386,14 +1369,11 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
* We take the 'long' return path, and there every subsystem
* grabs the apropriate locks (kernel lock/ irq lock).
*
- * FIXME: we want to decouple profiling from the 'long path'.
+ * we might want to decouple profiling from the 'long path',
+ * and do the profiling totally in assembly.
*
* Currently this isnt too much of an issue (performancewise),
* we can take more than 100K local irqs per second on a 100 MHz P5.
- * [ although we notice need_resched too early, thus the way we
- * schedule (deliver signals and handle bhs) changes. ]
- *
- * Possibly we could solve these problems with 'smart irqs'.
*/
}
@@ -1401,6 +1381,9 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs)
* Local APIC timer interrupt. This is the most natural way for doing
* local interrupts, but local timer interrupts can be emulated by
* broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ *
+ * [ if a single-CPU system runs an SMP kernel then we call the local
+ * interrupt as well. Thus we cannot inline the local irq ... ]
*/
void smp_apic_timer_interrupt(struct pt_regs * regs)
{
@@ -1415,7 +1398,7 @@ void smp_apic_timer_interrupt(struct pt_regs * regs)
smp_local_timer_interrupt(regs);
}
-/*
+/*
* Reschedule call back
*/
asmlinkage void smp_reschedule_interrupt(void)
@@ -1437,11 +1420,11 @@ asmlinkage void smp_reschedule_interrupt(void)
*/
asmlinkage void smp_invalidate_interrupt(void)
{
- if (clear_bit(smp_processor_id(), &smp_invalidate_needed))
+ if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
local_flush_tlb();
ack_APIC_irq ();
-}
+}
/*
* CPU halt call-back
@@ -1471,11 +1454,11 @@ asmlinkage void smp_stop_cpu_interrupt(void)
* but we do not accept timer interrupts yet. We only allow the BP
* to calibrate.
*/
-static unsigned int get_8254_timer_count (void)
+__initfunc(static unsigned int get_8254_timer_count (void))
{
unsigned int count;
- outb_p(0x00, 0x43);
+ outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
@@ -1500,7 +1483,7 @@ static unsigned int get_8254_timer_count (void)
void setup_APIC_timer (unsigned int clocks)
{
- unsigned long lvtt1_value;
+ unsigned long lvtt1_value;
unsigned int tmp_value;
/*
@@ -1508,8 +1491,8 @@ void setup_APIC_timer (unsigned int clocks)
* mode. With the IO APIC we can re-route the external timer
* interrupt and broadcast it as an NMI to all CPUs, so no pain.
*
- * NOTE: this trap vector (0x41) and the gate in BUILD_SMP_TIMER_INTERRUPT
- * should be the same ;)
+ * NOTE: this trap vector (0x41) and the gate in
+ * BUILD_SMP_TIMER_INTERRUPT should be the same ;)
*/
tmp_value = apic_read(APIC_LVTT);
lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41;
@@ -1526,7 +1509,7 @@ void setup_APIC_timer (unsigned int clocks)
apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
}
-void wait_8254_wraparound (void)
+__initfunc(void wait_8254_wraparound (void))
{
unsigned int curr_count, prev_count=~0;
int delta;
@@ -1560,11 +1543,12 @@ void wait_8254_wraparound (void)
* APIC irq that way.
*/
-int calibrate_APIC_clock (void)
+__initfunc(int calibrate_APIC_clock (void))
{
unsigned long long t1,t2;
long tt1,tt2;
long calibration_result;
+ int i;
printk("calibrating APIC timer ... ");
@@ -1589,10 +1573,12 @@ int calibrate_APIC_clock (void)
RTDSC(t1);
tt1=apic_read(APIC_TMCCT);
+#define LOOPS (HZ/10)
/*
- * lets wait until we get to the next wrapround:
+ * lets wait LOOPS wraprounds:
*/
- wait_8254_wraparound ();
+ for (i=0; i<LOOPS; i++)
+ wait_8254_wraparound ();
tt2=apic_read(APIC_TMCCT);
RTDSC(t2);
@@ -1605,46 +1591,47 @@ int calibrate_APIC_clock (void)
* underflown to be exact, as the timer counts down ;)
*/
- calibration_result = (tt1-tt2)*APIC_DIVISOR;
+ calibration_result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
- printk("\n..... %ld CPU clocks in 1 timer chip tick.\n",
- (unsigned long)(t2-t1));
+ SMP_PRINTK(("\n..... %ld CPU clocks in 1 timer chip tick.",
+ (unsigned long)(t2-t1)/LOOPS));
- printk("..... %ld APIC bus clocks in 1 timer chip tick.\n",
- calibration_result);
+ SMP_PRINTK(("\n..... %ld APIC bus clocks in 1 timer chip tick.",
+ calibration_result));
- printk("..... CPU clock speed is %ld.%ld MHz.\n",
- ((long)(t2-t1))/(1000000/HZ),
- ((long)(t2-t1))%(1000000/HZ) );
+ printk("\n..... CPU clock speed is %ld.%04ld MHz.\n",
+ ((long)(t2-t1)/LOOPS)/(1000000/HZ),
+ ((long)(t2-t1)/LOOPS)%(1000000/HZ) );
- printk("..... APIC bus clock speed is %ld.%ld MHz.\n",
+ printk("..... APIC bus clock speed is %ld.%04ld MHz.\n",
calibration_result/(1000000/HZ),
calibration_result%(1000000/HZ) );
+#undef LOOPS
return calibration_result;
}
static unsigned int calibration_result;
-void setup_APIC_clock (void)
+__initfunc(void setup_APIC_clock (void))
{
int cpu = smp_processor_id();
- unsigned long flags;
+ unsigned long flags;
static volatile int calibration_lock;
save_flags(flags);
cli();
- printk("setup_APIC_clock() called.\n");
+ SMP_PRINTK(("setup_APIC_clock() called.\n"));
/*
* [ setup_APIC_clock() is called from all CPUs, but we want
* to do this part of the setup only once ... and it fits
* here best ]
*/
- if (!set_bit(0,&calibration_lock)) {
+ if (!test_and_set_bit(0,&calibration_lock)) {
calibration_result=calibrate_APIC_clock();
/*
@@ -1656,9 +1643,9 @@ void setup_APIC_clock (void)
/*
* Other CPU is calibrating, wait for finish:
*/
- printk("waiting for other CPU calibrating APIC timer ... ");
+ SMP_PRINTK(("waiting for other CPU calibrating APIC ... "));
while (calibration_lock == 1);
- printk("done, continuing.\n");
+ SMP_PRINTK(("done, continuing.\n"));
}
/*
@@ -1669,16 +1656,8 @@ void setup_APIC_clock (void)
prof_counter[cpu] = prof_multiplier[cpu] = 1;
/*
- * FIXME: i sporadically see booting problems (keyboard irq is
- * lost, looks like the timer irq isnt working or some irq
- * lock is messed up). Once we reboot the bug doesnt showu
- * up anymore.
- *
- * i'm quite certain it's a timing problem/race condition in
- * the bootup logic, not a hw bug. It might have been gone
- * meanwhile, tell me if you see it.
+ * We ACK the APIC, just in case there is something pending.
*/
-
ack_APIC_irq ();
restore_flags(flags);
@@ -1686,7 +1665,7 @@ void setup_APIC_clock (void)
/*
* the frequency of the profiling timer can be changed
- * by writing 4 bytes into /proc/profile.
+ * by writing a multiplier value into /proc/profile.
*
* usually you want to run this on all CPUs ;)
*/
@@ -1697,8 +1676,8 @@ int setup_profiling_timer (unsigned int multiplier)
/*
* Sanity check. [at least 500 APIC cycles should be
- * between APIC interrupts as a rule of thumb, rather be
- * careful as irq flooding renders the system unusable]
+ * between APIC interrupts as a rule of thumb, to avoid
+ * irqs flooding us]
*/
if ( (!multiplier) || (calibration_result/multiplier < 500))
return -EINVAL;
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 6a7d6b461..e45cc7279 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -23,6 +23,7 @@
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/smp.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -379,11 +380,15 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do_timer(regs);
/*
* In the SMP case we use the local APIC timer interrupt to do the
- * profiling.
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
*/
#ifndef __SMP__
if (!user_mode(regs))
x86_do_profile(regs->eip);
+#else
+ if (!smp_found_config)
+ smp_local_timer_interrupt(regs);
#endif
/*
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index 63bc51c5e..d0a726f6b 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -21,13 +21,9 @@
* and IP is zero. Thus, data addresses need to be absolute
* (no relocation) and are taken with regard to r_base.
*
- * On the transition to protected mode, this page appears at
- * address 8192, so protected mode addresses are with regard
- * to p_base.
- *
* If you work on this file, check the object module with objdump
* --full-contents --reloc to make sure there are no relocation
- * entries.
+ * entries except for the gdt one..
*/
#include <linux/linkage.h>
@@ -39,15 +35,10 @@
ENTRY(trampoline_data)
r_base = .
-p_base = . - 8192
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
- mov %ax, %cx # Pass stack info to the 32bit boot
- shl $4, %cx # Segment -> Offset
- add $4096, %cx # End of page is wanted
-
mov $1, %bx # Flag an SMP trampoline
cli # We should be safe anyway
@@ -71,37 +62,7 @@ idt_48:
gdt_48:
.word 0x0800 # gdt limit = 2048, 256 GDT entries
- .word gdt - p_base, 0x0 # gdt base = gdt (first SMP CPU)
- # we load the others with first table
- # saves rewriting gdt_48 for each
-gdt:
- .word 0, 0, 0, 0 # dummy
-
- .word 0, 0, 0, 0 # unused
-
-# walken modif
-
- .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 # base address = 0
- .word 0x9A00 # code read / exec
- .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit)
-
- .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 # base address = 0
- .word 0x9200 # data read / write
- .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit)
-
-# walken modif
-
-# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-# .word 0x0000 # base address = 0
-# .word 0x9A00 # code read / exec
-# .word 0x00C0 # granularity = 4096, 386
-
-# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-# .word 0x0000 # base address = 0
-# .word 0x9200 # data read / write
-# .word 0x00C0 # granularity = 4096, 386
+ .long gdt-0xc0000000 # gdt base = gdt (first SMP CPU)
.globl SYMBOL_NAME(trampoline_end)
SYMBOL_NAME_LABEL(trampoline_end)
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 905cf5b13..696e37004 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -23,10 +23,12 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/spinlock.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
@@ -121,7 +123,7 @@ static void show_registers(struct pt_regs *regs)
unsigned long esp;
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, _etext;
+ extern char _stext, _etext;
esp = (unsigned long) &regs->esp;
ss = KERNEL_DS;
@@ -129,8 +131,8 @@ static void show_registers(struct pt_regs *regs)
esp = regs->esp;
ss = regs->xss & 0xffff;
}
- printk("CPU: %d\n", smp_processor_id());
- printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags);
+ printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n",
+ smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags);
printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
@@ -138,10 +140,8 @@ static void show_registers(struct pt_regs *regs)
printk("ds: %04x es: %04x ss: %04x\n",
regs->xds & 0xffff, regs->xes & 0xffff, ss);
store_TR(i);
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i, current->kernel_stack_page);
+ current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current);
stack = (unsigned long *) esp;
for(i=0; i < kstack_depth_to_print; i++) {
if (((long) stack & 4095) == 0)
@@ -166,7 +166,7 @@ static void show_registers(struct pt_regs *regs)
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
- if (((addr >= (unsigned long) &start_kernel) &&
+ if (((addr >= (unsigned long) &_stext) &&
(addr <= (unsigned long) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
@@ -181,13 +181,19 @@ static void show_registers(struct pt_regs *regs)
printk("\n");
}
+spinlock_t die_lock;
+
/*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3)
return;
console_verbose();
+ spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
+do { int i=2000000000; while (i) i--; } while (0);
+do { int i=2000000000; while (i) i--; } while (0);
+ spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
@@ -235,18 +241,45 @@ out:
unlock_kernel();
}
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
{
- printk("NMI\n"); show_registers(regs);
-#ifdef CONFIG_SMP_NMI_INVAL
- smp_flush_tlb_rcv();
-#else
-#ifndef CONFIG_IGNORE_NMI
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
- printk("You probably have a hardware problem with your RAM chips or a\n");
- printk("power saving mode enabled.\n");
-#endif
-#endif
+ printk("You probably have a hardware problem with your RAM chips\n");
+}
+
+static void io_check_error(unsigned char reason, struct pt_regs * regs)
+{
+ unsigned long i;
+
+ printk("NMI: IOCK error (debug interrupt?)\n");
+ show_registers(regs);
+
+ /* Re-enable the IOCK line, wait for a few seconds */
+ reason |= 8;
+ outb(reason, 0x61);
+ i = 2000;
+ while (--i) udelay(1000);
+ reason &= ~8;
+ outb(reason, 0x61);
+}
+
+static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+ printk("Dazed and confused, but trying to continue\n");
+ printk("Do you have a strange power saving mode enabled?\n");
+}
+
+asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+{
+ unsigned char reason = inb(0x61);
+
+ if (reason & 0x80)
+ mem_parity_error(reason, regs);
+ if (reason & 0x40)
+ io_check_error(reason, regs);
+ if (!(reason & 0xc0))
+ unknown_nmi_error(reason, regs);
}
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -380,15 +413,7 @@ __initfunc(void trap_init(void))
{
int i;
struct desc_struct * p;
- static int smptrap=0;
-
- if(smptrap)
- {
- __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
- load_ldt(0);
- return;
- }
- smptrap++;
+
if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
set_call_gate(&default_ldt,lcall7);
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index bfba24327..a09fa6419 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -81,8 +81,8 @@ asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
printk("vm86: could not access userspace vm86_info\n");
do_exit(SIGSEGV);
}
- current->tss.esp0 = current->saved_kernel_stack;
- current->saved_kernel_stack = 0;
+ current->tss.esp0 = current->tss.saved_esp0;
+ current->tss.saved_esp0 = 0;
ret = KVM86->regs32;
unlock_kernel();
return ret;
@@ -137,7 +137,7 @@ asmlinkage int sys_vm86old(struct vm86_struct * v86)
lock_kernel();
tsk = current;
- if (tsk->saved_kernel_stack)
+ if (tsk->tss.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -187,7 +187,7 @@ asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86)
/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
ret = -EPERM;
- if (tsk->saved_kernel_stack)
+ if (tsk->tss.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -247,7 +247,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
* Save old state, set default return value (%eax) to 0
*/
info->regs32->eax = 0;
- tsk->saved_kernel_stack = tsk->tss.esp0;
+ tsk->tss.saved_esp0 = tsk->tss.esp0;
tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
tsk->tss.screen_bitmap = info->screen_bitmap;
@@ -601,11 +601,17 @@ static inline void free_vm86_irq(int irqnumber)
static inline int task_valid(struct task_struct *tsk)
{
struct task_struct *p;
+ int ret = 0;
+ read_lock(&tasklist_lock);
for_each_task(p) {
- if ((p == tsk) && (p->sig)) return 1;
+ if ((p == tsk) && (p->sig)) {
+ ret = 1;
+ break;
+ }
}
- return 0;
+ read_unlock(&tasklist_lock);
+ return ret;
}
static inline void handle_irq_zombies(void)
diff --git a/arch/i386/lib/locks.S b/arch/i386/lib/locks.S
index b9d8b0a9c..30a5bc432 100644
--- a/arch/i386/lib/locks.S
+++ b/arch/i386/lib/locks.S
@@ -10,22 +10,25 @@
* %eax contains callers PC and %edx holds this cpu ID.
*/
ENTRY(__lock_kernel)
- pushl %eax ! return address
1:
lock
btsl $0, SYMBOL_NAME(kernel_flag)
jnc 3f
+ sti
2:
btl %dl, SYMBOL_NAME(smp_invalidate_needed)
jnc 0f
lock
btrl %dl, SYMBOL_NAME(smp_invalidate_needed)
jnc 0f
+ pushl %eax
movl %cr3, %eax
movl %eax, %cr3
+ popl %eax
0:
btl $0, SYMBOL_NAME(kernel_flag)
jc 2b
+ cli
jmp 1b
3:
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
index ff2443c40..faddbf4ec 100644
--- a/arch/i386/lib/semaphore.S
+++ b/arch/i386/lib/semaphore.S
@@ -13,16 +13,17 @@
* there is contention on the semaphore.
*/
ENTRY(__down_failed)
- pushl %eax /* return address */
+ pushl %eax /* save %eax */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__down)
popl %ecx /* restore %ecx (count on __down not changing it) */
popl %edx /* restore %edx */
+ popl %eax /* restore %eax */
ret
+/* Don't save/restore %eax, because that will be our return value */
ENTRY(__down_failed_interruptible)
- pushl %eax /* return address */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__down_interruptible)
@@ -31,10 +32,11 @@ ENTRY(__down_failed_interruptible)
ret
ENTRY(__up_wakeup)
- pushl %eax /* return address */
+ pushl %eax /* save %eax */
pushl %edx /* save %edx */
pushl %ecx /* save %ecx (and argument) */
call SYMBOL_NAME(__up)
popl %ecx /* restore %ecx (count on __up not changing it) */
popl %edx /* restore %edx */
+ popl %eax /* restore %eax */
ret
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 65a4a67d3..b0404a6a9 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -49,7 +49,7 @@ good_area:
start &= PAGE_MASK;
for (;;) {
- do_wp_page(current, vma, start, 1);
+ handle_mm_fault(current,vma, start, 1);
if (!size)
break;
size--;
@@ -86,10 +86,6 @@ bad_area:
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
- void (*handler)(struct task_struct *,
- struct vm_area_struct *,
- unsigned long,
- int);
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
struct vm_area_struct * vma;
@@ -128,10 +124,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
*/
good_area:
write = 0;
- handler = do_no_page;
switch (error_code & 3) {
default: /* 3: write, present */
- handler = do_wp_page;
#ifdef TEST_VERIFY_AREA
if (regs->cs == KERNEL_CS)
printk("WP fault at %08lx\n", regs->eip);
@@ -148,7 +142,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handler(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
up(&mm->mmap_sem);
/*
* Did it hit the DOS screen memory VA from vm86 mode?
@@ -169,7 +163,10 @@ bad_area:
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->eip)) != 0) {
- printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup);
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+ current->comm,
+ regs->eip,
+ fixup);
regs->eip = fixup;
goto out;
}
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 173649338..c8371aa81 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -139,12 +139,23 @@ extern char __init_begin, __init_end;
#define write_cr4 ".byte 0x0f,0x22,0xe0"
#endif
-#define set_in_cr4(x) \
-__asm__(read_cr4 "\n\t" \
- "orl %0,%%eax\n\t" \
- write_cr4 \
- : : "i" (x) \
- :"ax");
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+unsigned long mmu_cr4_features __initdata = 0;
+
+static inline void set_in_cr4(unsigned long mask)
+{
+ mmu_cr4_features |= mask;
+ __asm__(read_cr4 "\n\t"
+ "orl %0,%%eax\n\t"
+ write_cr4
+ : : "irg" (mask)
+ :"ax");
+}
/*
* paging_init() sets up the page tables - note that the first 4MB are
diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds
index 6d1195013..7a1fd3d08 100644
--- a/arch/i386/vmlinux.lds
+++ b/arch/i386/vmlinux.lds
@@ -13,6 +13,7 @@ SECTIONS
*(.fixup)
*(.gnu.warning)
} = 0x9090
+ .text.lock : { *(.text.lock) } /* out-of-line lock text */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 939a80387..7548a8dc8 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -24,19 +24,9 @@ ifneq ($(COMPILE_ARCH),$(ARCH))
CROSS_COMPILE = m68k-linux-
endif
-#
-# Set these to indicate how to link it..
-#
-# -zmagic:
-#
-# LINKFLAGS = -Ttext 0x100000
-#
-# -qmagic (we need to remove the 32 byte header for bootup purposes)
-#
-
-LINKFLAGS = -Ttext 0x1000
+LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
-CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce
+CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
ifdef CONFIG_OPTIMIZE_040
CFLAGS := $(CFLAGS) -m68040
diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c
index c97609611..eb72970d7 100644
--- a/arch/m68k/amiga/amifb.c
+++ b/arch/m68k/amiga/amifb.c
@@ -50,12 +50,14 @@
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
-#include <linux/fb.h>
#define DEBUG
@@ -1802,7 +1804,7 @@ static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
* Initialisation
*/
-struct fb_info *amiga_fb_init(long *mem_start)
+__initfunc(struct fb_info *amiga_fb_init(long *mem_start))
{
int err, tag, i;
u_long chipptr;
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index b527a8c6c..9df5083c1 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -68,7 +69,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
* the amiga IRQ handling routines.
*/
-void amiga_init_IRQ(void)
+__initfunc(void amiga_init_IRQ(void))
{
int i;
diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c
index f2e826023..1058270dd 100644
--- a/arch/m68k/amiga/amikeyb.c
+++ b/arch/m68k/amiga/amikeyb.c
@@ -22,6 +22,7 @@
#include <linux/kd.h>
#include <linux/random.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
@@ -295,7 +296,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
}
}
-int amiga_keyb_init(void)
+__initfunc(int amiga_keyb_init(void))
{
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -EIO;
diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
index b2b2e3055..d5656d170 100644
--- a/arch/m68k/amiga/amisound.c
+++ b/arch/m68k/amiga/amisound.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/amigahw.h>
@@ -39,7 +40,7 @@ u_short amiga_audio_period = MAX_PERIOD;
static u_long clock_constant;
-static void init_sound(void)
+__initfunc(static void init_sound(void))
{
snd_data = amiga_chip_alloc(sizeof(sine_data));
if (!snd_data) {
@@ -84,7 +85,7 @@ void amiga_mksound( unsigned int hz, unsigned int ticks )
custom.aud[2].audlc = snd_data;
custom.aud[2].audlen = sizeof(sine_data)/2;
custom.aud[2].audper = (u_short)period;
- custom.aud[2].audvol = 64; /* maxvol */
+ custom.aud[2].audvol = 32; /* 50% of maxvol */
if (ticks) {
sound_timer.expires = jiffies + ticks;
diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c
index 237662c93..50d5a0de0 100644
--- a/arch/m68k/amiga/chipram.c
+++ b/arch/m68k/amiga/chipram.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <asm/amigahw.h>
struct chip_desc {
@@ -21,19 +22,18 @@ struct chip_desc {
#define DP(ptr) ((struct chip_desc *)(ptr))
u_long amiga_chip_size;
-static unsigned long chipavail; /*MILAN*/
+static unsigned long chipavail;
-/*MILAN*/
unsigned long amiga_chip_avail( void )
{
#ifdef DEBUG
- printk("chip_avail : %ld bytes\n",chipavail);
+ printk("chip_avail : %ld bytes\n",chipavail);
#endif
- return chipavail;
+ return chipavail;
}
-void amiga_chip_init (void)
+__initfunc(void amiga_chip_init (void))
{
struct chip_desc *dp;
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 02b1ad564..408dcbf5a 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
@@ -152,7 +153,7 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
amiga_do_irq_list(base->server_irq, fp, &base->server);
}
-void cia_init_IRQ(struct ciabase *base)
+__initfunc(void cia_init_IRQ(struct ciabase *base))
{
int i;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 8e6ae531c..08396a5bc 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -20,6 +20,7 @@
#include <linux/kd.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -148,7 +149,7 @@ int amiga_parse_bootinfo(const struct bi_record *record)
* Setup the Amiga configuration info
*/
-void config_amiga(void)
+__initfunc(void config_amiga(void))
{
/* Fill in some default values, if necessary */
if (amiga_eclock == 0)
@@ -376,8 +377,8 @@ void config_amiga(void)
static unsigned short jiffy_ticks;
-static void amiga_sched_init(void (*timer_routine)(int, void *,
- struct pt_regs *))
+__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
+ struct pt_regs *)))
{
jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
@@ -796,7 +797,7 @@ void amiga_serial_gets(char *s, int len)
}
#endif
-static void amiga_debug_init(void)
+__initfunc(static void amiga_debug_init(void))
{
if (!strcmp( m68k_debug_device, "ser" )) {
/* no initialization required (?) */
diff --git a/arch/m68k/amiga/cyberfb.c b/arch/m68k/amiga/cyberfb.c
index d74d52c4f..31e2a4608 100644
--- a/arch/m68k/amiga/cyberfb.c
+++ b/arch/m68k/amiga/cyberfb.c
@@ -29,12 +29,13 @@
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
+#include <linux/zorro.h>
+#include <linux/fb.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
-#include <linux/zorro.h>
#include <asm/pgtable.h>
-#include <linux/fb.h>
#include "s3blit.h"
@@ -1157,7 +1158,7 @@ void Cyber_video_setup(char *options, int *ints)
* Initialization
*/
-struct fb_info *Cyber_fb_init(long *mem_start)
+__initfunc(struct fb_info *Cyber_fb_init(long *mem_start))
{
int err;
struct Cyber_fb_par par;
diff --git a/arch/m68k/amiga/retz3fb.c b/arch/m68k/amiga/retz3fb.c
index 4885e48f7..49a0853bc 100644
--- a/arch/m68k/amiga/retz3fb.c
+++ b/arch/m68k/amiga/retz3fb.c
@@ -30,1762 +30,12 @@
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/fb.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
#include <linux/zorro.h>
-#include <asm/pgtable.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-struct retz3_fb_par {
- int xres;
- int yres;
- int xres_vir;
- int yres_vir;
- int xoffset;
- int yoffset;
- int bpp;
-
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
-
- int pixclock;
- int left_margin; /* time from sync to picture */
- int right_margin; /* time from picture to sync */
- int upper_margin; /* time from sync to picture */
- int lower_margin;
- int hsync_len; /* length of horizontal sync */
- int vsync_len; /* length of vertical sync */
- int vmode;
-};
-
-struct display_data {
- long h_total; /* Horizontal Total */
- long h_sstart; /* Horizontal Sync Start */
- long h_sstop; /* Horizontal Sync Stop */
- long h_bstart; /* Horizontal Blank Start */
- long h_bstop; /* Horizontal Blank Stop */
- long h_dispend; /* Horizontal Display End */
- long v_total; /* Vertical Total */
- long v_sstart; /* Vertical Sync Start */
- long v_sstop; /* Vertical Sync Stop */
- long v_bstart; /* Vertical Blank Start */
- long v_bstop; /* Vertical Blank Stop */
- long v_dispend; /* Horizontal Display End */
-};
-
-static struct retz3_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node; /* node of the /dev/fb?current file */
-
-
-/*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
-
- int (*init)(void);
-
- /* Display Control */
-
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
- int *green, unsigned int *blue, unsigned int *transp);
- int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
- green, unsigned int blue, unsigned int transp);
- void (*blank)(int blank);
-} *fbhw;
-
-
-/*
- * Frame Buffer Name
- */
-
-static char retz3_fb_name[16] = "RetinaZ3";
-
-
-static int z3_key = 0;
-static unsigned char retz3_color_table [256][4];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-static long *memstart;
-
-
-/*
- * Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "640x480", /* RetinaZ3 8 bpp */
- "800x600", /* RetinaZ3 8 bpp */
- "1024x768i",
- "640x480-16", /* RetinaZ3 16 bpp */
- "640x480-24", /* RetinaZ3 24 bpp */
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3",
- "user4", "user5", "user6", "user7"
-};
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600" 50 800 856 976 1040 600 637 643 666
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
-
-The fields in the fb_var_screeninfo structure are:
- unsigned long pixclock; * pixel clock in ps (pico seconds) *
- unsigned long left_margin; * time from sync to picture *
- unsigned long right_margin; * time from picture to sync *
- unsigned long upper_margin; * time from sync to picture *
- unsigned long lower_margin;
- unsigned long hsync_len; * length of horizontal sync *
- unsigned long vsync_len; * length of vertical sync *
-
-1) Pixelclock:
- xfree: in MHz
- fb: In Picoseconds (ps)
-
- pixclock = 1000000 / DCF
-
-2) horizontal timings:
- left_margin = HFL - SH2
- right_margin = SH1 - HR
- hsync_len = SH2 - SH1
-
-3) vertical timings:
- upper_margin = VFL - SV2
- lower_margin = SV1 - VR
- vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- * Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- /*
- * NB: it is very important to adjust the pixel-clock to the color-depth.
- */
-
- {
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 800 x 600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 1024 x 768, 8 bpp, interlaced */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 24, 0,
- {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
-
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES (5)
-
-
-static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
-
-
-/*
- * Interface used by the world
- */
-
-int retz3_probe(void);
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con);
-
-
-/*
- * Interface to the low level console driver
- */
-
-struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
-
-
-/*
- * Accelerated Functions used by the low level console driver
- */
-
-void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short curx, unsigned short cury, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
- width, unsigned short height, unsigned short mode,
- unsigned short color);
-
-/*
- * Hardware Specific Routines
- */
-
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp);
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp);
-static void retz3_blank(int blank);
-
-
-/*
- * Internal routines
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void retz3_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
- unsigned long f;
- long tmp;
- long prev = 0x7fffffff;
- long n2, n1 = 3;
- unsigned long m;
- unsigned short res = 0;
-
- if (freq <= 31250000)
- n2 = 3;
- else if (freq <= 62500000)
- n2 = 2;
- else if (freq <= 125000000)
- n2 = 1;
- else if (freq <= 250000000)
- n2 = 0;
- else
- return(0);
-
-
- do {
- f = freq >> (10 - n2);
-
- m = (f * n1) / (14318180/1024);
-
- if (m > 129)
- break;
-
- tmp = (((m * 14318180) >> n2) / n1) - freq;
- if (tmp < 0)
- tmp = -tmp;
-
- if (tmp < prev) {
- prev = tmp;
- res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
- }
-
- } while ( (++n1) <= 21);
-
- return res;
-}
-
-
-static int retz3_set_video(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- float freq_f;
- long freq;
-
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- unsigned char tmp;
- unsigned short best_freq;
- struct display_data data;
-
- short clocksel = 0; /* Apparantly this is always zero */
-
- int bpp = var->bits_per_pixel;
-
- /*
- * XXX
- */
- if (bpp == 24)
- return 0;
-
- if ((bpp != 8) && (bpp != 16) && (bpp != 24))
- return -EFAULT;
-
- par->xoffset = 0;
- par->yoffset = 0;
-
- xres = var->xres * bpp / 4;
- hfront = var->right_margin * bpp / 4;
- hsync = var->hsync_len * bpp / 4;
- hback = var->left_margin * bpp / 4;
-
- if (var->vmode & FB_VMODE_DOUBLE)
- {
- yres = var->yres * 2;
- vfront = var->lower_margin * 2;
- vsync = var->vsync_len * 2;
- vback = var->upper_margin * 2;
- }
- else if (var->vmode & FB_VMODE_INTERLACED)
- {
- yres = (var->yres + 1) / 2;
- vfront = (var->lower_margin + 1) / 2;
- vsync = (var->vsync_len + 1) / 2;
- vback = (var->upper_margin + 1) / 2;
- }
- else
- {
- yres = var->yres; /* -1 ? */
- vfront = var->lower_margin;
- vsync = var->vsync_len;
- vback = var->upper_margin;
- }
-
- data.h_total = (hback / 8) + (xres / 8)
- + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
- data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
- data.h_bstart = xres / 8 /* + 1 */;
-
- data.h_bstop = data.h_total+1 + 2 + 1;
- data.h_sstart = (xres / 8) + (hfront / 8) + 1;
- data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
- data.v_total = yres + vfront + vsync + vback - 1;
-
- data.v_dispend = yres - 1;
- data.v_bstart = yres;
-
- data.v_bstop = data.v_total;
- data.v_sstart = yres + vfront - 1 - 2;
- data.v_sstop = yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
- printk("HBS: %i\n", data.h_bstart);
- printk("HSS: %i\n", data.h_sstart);
- printk("HSE: %i\n", data.h_sstop);
- printk("HBE: %i\n", data.h_bstop);
- printk("HT: %i\n", data.h_total);
-
- printk("hsync: %i\n", hsync);
- printk("hfront: %i\n", hfront);
- printk("hback: %i\n", hback);
-
- printk("VBS: %i\n", data.v_bstart);
- printk("VSS: %i\n", data.v_sstart);
- printk("VSE: %i\n", data.v_sstop);
- printk("VBE: %i\n", data.v_bstop);
- printk("VT: %i\n", data.v_total);
-
- printk("vsync: %i\n", vsync);
- printk("vfront: %i\n", vfront);
- printk("vback: %i\n", vback);
-#endif
-
- if (data.v_total >= 1024)
- printk("MAYDAY: v_total >= 1024; bailing out!\n");
-
- reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
- reg_w(GREG_FEATURE_CONTROL_W, 0x00);
-
- seq_w(SEQ_RESET, 0x00);
- seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
-
- /*
- * CLOCKING_MODE bits:
- * 2: This one is only set for certain text-modes, wonder if
- * it may be for EGA-lines? (it was referred to as CLKDIV2)
- * (The CL drivers sets it to 0x21 with the comment:
- * FullBandwidth (video off) and 8/9 dot clock)
- */
- seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
- seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
- seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
- seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
- seq_w(SEQ_RESET, 0x01);
- seq_w(SEQ_RESET, 0x03);
-
- seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
- seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_LINEAR_0, 0x4a);
- seq_w(SEQ_LINEAR_1, 0x00);
-
- seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
- seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
- seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
- /*
- * The lower 4 bits (0-3) are used to set the font-width for
- * text-mode - DON'T try to set this for gfx-mode.
- */
- seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
- seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
-
- /*
- * Extended Pixel Control:
- * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
- * bit 1: (Packed/Nibble Pixel Format ?)
- * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
- */
- seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
- seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
- seq_w(SEQ_COLOR_EXP_WFG, 0x01);
- seq_w(SEQ_COLOR_EXP_WBG, 0x00);
- seq_w(SEQ_EXT_RW_CONTROL, 0x00);
- seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
- seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
- seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
- seq_w(SEQ_CRC_CONTROL, 0x00);
- seq_w(SEQ_PERF_SELECT, 0x10);
- seq_w(SEQ_ACM_APERTURE_1, 0x00);
- seq_w(SEQ_ACM_APERTURE_2, 0x30);
- seq_w(SEQ_ACM_APERTURE_3, 0x00);
- seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
- /* unlock register CRT0..CRT7 */
- crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
- /* Zuerst zu schreibende Werte nur per printk ausgeben */
- DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
- crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
-
- DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
- crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
- DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
- crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
- DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
- crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
-
- DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
- crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
- tmp = (data.h_sstop & 0x1f);
- if (data.h_bstop & 0x20)
- tmp |= 0x80;
- DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
- crt_w(CRT_END_HOR_RETR, tmp);
-
- DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
- crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
-
- tmp = 0x10; /* LineCompare bit #9 */
- if (data.v_total & 256)
- tmp |= 0x01;
- if (data.v_dispend & 256)
- tmp |= 0x02;
- if (data.v_sstart & 256)
- tmp |= 0x04;
- if (data.v_bstart & 256)
- tmp |= 0x08;
- if (data.v_total & 512)
- tmp |= 0x20;
- if (data.v_dispend & 512)
- tmp |= 0x40;
- if (data.v_sstart & 512)
- tmp |= 0x80;
- DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
- crt_w(CRT_OVERFLOW, tmp);
-
- crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
- tmp = 0x40; /* LineCompare bit #8 */
- if (data.v_bstart & 512)
- tmp |= 0x20;
- if (var->vmode & FB_VMODE_DOUBLE)
- tmp |= 0x80;
- DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
- crt_w(CRT_MAX_SCAN_LINE, tmp);
-
- crt_w(CRT_CURSOR_START, 0x00);
- crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
- crt_w(CRT_START_ADDR_HIGH, 0x00);
- crt_w(CRT_START_ADDR_LOW, 0x00);
-
- crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
- crt_w(CRT_CURSOR_LOC_LOW, 0x00);
-
- DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
- crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
- /* 5 refresh cycles per scanline */
- DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
- DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
- DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
- crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
- DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
- crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
- DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
- crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
- DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
- crt_w(CRT_MODE_CONTROL, 0xe3);
-
- DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
- crt_w(CRT_LINE_COMPARE, 0xff);
-
- tmp = (var->xres_virtual / 8) * (bpp / 8);
- crt_w(CRT_OFFSET, tmp);
-
- crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
- tmp = 0x20; /* Enable extended end bits */
- if (data.h_total & 0x100)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x100)
- tmp |= 0x02;
- if (data.h_bstart & 0x100)
- tmp |= 0x04;
- if (data.h_sstart & 0x100)
- tmp |= 0x08;
- if (var->vmode & FB_VMODE_INTERLACED)
- tmp |= 0x10;
- DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
- crt_w(CRT_EXT_HOR_TIMING1, tmp);
-
- tmp = 0x00;
- if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
- tmp |= 0x10;
- crt_w(CRT_EXT_START_ADDR, tmp);
-
- tmp = 0x00;
- if (data.h_total & 0x200)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x200)
- tmp |= 0x02;
- if (data.h_bstart & 0x200)
- tmp |= 0x04;
- if (data.h_sstart & 0x200)
- tmp |= 0x08;
- tmp |= ((data.h_bstop & 0xc0) >> 2);
- tmp |= ((data.h_sstop & 0x60) << 1);
- crt_w(CRT_EXT_HOR_TIMING2, tmp);
- DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
- tmp = 0x10; /* Line compare bit 10 */
- if (data.v_total & 0x400)
- tmp |= 0x01;
- if ((data.v_dispend) & 0x400)
- tmp |= 0x02;
- if (data.v_bstart & 0x400)
- tmp |= 0x04;
- if (data.v_sstart & 0x400)
- tmp |= 0x08;
- tmp |= ((data.v_bstop & 0x300) >> 3);
- if (data.v_sstop & 0x10)
- tmp |= 0x80;
- crt_w(CRT_EXT_VER_TIMING, tmp);
- DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
- crt_w(CRT_MONITOR_POWER, 0x00);
-
- /*
- * Convert from ps to Hz.
- */
- freq_f = (1.0/(float)var->pixclock) * 1000000000;
- freq = ((long)freq_f) * 1000;
-
- best_freq = find_fq(freq);
- pll_w(0x02, best_freq);
- best_freq = find_fq(61000000);
- pll_w(0x0a, best_freq);
- pll_w(0x0e, 0x22);
-
- gfx_w(GFX_SET_RESET, 0x00);
- gfx_w(GFX_ENABLE_SET_RESET, 0x00);
- gfx_w(GFX_COLOR_COMPARE, 0x00);
- gfx_w(GFX_DATA_ROTATE, 0x00);
- gfx_w(GFX_READ_MAP_SELECT, 0x00);
- gfx_w(GFX_GRAPHICS_MODE, 0x00);
- gfx_w(GFX_MISC, 0x05);
- gfx_w(GFX_COLOR_XCARE, 0x0f);
- gfx_w(GFX_BITMASK, 0xff);
-
- reg_r(ACT_ADDRESS_RESET);
- attr_w(ACT_PALETTE0 , 0x00);
- attr_w(ACT_PALETTE1 , 0x01);
- attr_w(ACT_PALETTE2 , 0x02);
- attr_w(ACT_PALETTE3 , 0x03);
- attr_w(ACT_PALETTE4 , 0x04);
- attr_w(ACT_PALETTE5 , 0x05);
- attr_w(ACT_PALETTE6 , 0x06);
- attr_w(ACT_PALETTE7 , 0x07);
- attr_w(ACT_PALETTE8 , 0x08);
- attr_w(ACT_PALETTE9 , 0x09);
- attr_w(ACT_PALETTE10, 0x0a);
- attr_w(ACT_PALETTE11, 0x0b);
- attr_w(ACT_PALETTE12, 0x0c);
- attr_w(ACT_PALETTE13, 0x0d);
- attr_w(ACT_PALETTE14, 0x0e);
- attr_w(ACT_PALETTE15, 0x0f);
- reg_r(ACT_ADDRESS_RESET);
-
- attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
- attr_w(ACT_OVERSCAN_COLOR, 0x00);
- attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
- attr_w(ACT_HOR_PEL_PANNING, 0x00);
- attr_w(ACT_COLOR_SELECT, 0x00);
-
- reg_r(ACT_ADDRESS_RESET);
- reg_w(ACT_DATA, 0x20);
-
- reg_w(VDAC_MASK, 0xff);
-
- /*
- * Extended palette adressing ???
- */
- switch (bpp){
- case 8:
- reg_w(0x83c6, 0x00);
- break;
- case 16:
- reg_w(0x83c6, 0x60);
- break;
- case 24:
- reg_w(0x83c6, 0xe0);
- break;
- default:
- printk("Illegal color-depth: %i\n", bpp);
- }
-
- reg_w(VDAC_ADDRESS, 0x00);
-
- seq_w(SEQ_MAP_MASK, 0x0f );
-
- return 0;
-}
-
-/*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
- int i;
-#if 0
- volatile unsigned long *CursorBase;
-#endif
- unsigned long board_addr, board_size;
- struct ConfigDev *cd;
-
- cd = zorro_get_board (z3_key);
- zorro_config_board (z3_key, 0);
- board_addr = (unsigned long)cd->cd_BoardAddr;
- board_size = (unsigned long)cd->cd_BoardSize;
-
- for (i = 0; i < 256; i++){
- for (i = 0; i < 256; i++){
- retz3_color_table [i][0] = i;
- retz3_color_table [i][1] = i;
- retz3_color_table [i][2] = i;
- retz3_color_table [i][3] = 0;
- }
- }
-
- *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- z3_mem = kernel_map (board_addr, board_size,
- KERNELMAP_NOCACHE_SER, memstart);
-
- z3_regs = (char*) z3_mem;
- z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
- /* Get memory size - for now we asume its a 4MB board */
-
- z3_size = 0x00400000; /* 4 MB */
-
- memset ((char*)z3_fbmem, 0, z3_size);
-
- /* Disable hardware cursor */
-
- seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-
-#if 0
- /* Initialize hardware cursor */
- CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
- for (i=0; i < 8; i++){
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i=8; i < 64; i++){
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-#endif
-
- retz3_setcolreg (255, 56, 100, 160, 0);
- retz3_setcolreg (254, 0, 0, 0, 0);
-
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par)
-{
- int i;
-
- strcpy(fix->id, retz3_fb_name);
- fix->smem_start = z3_fbmem;
- fix->smem_len = z3_size;
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_DIRECTCOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
-
- for (i = 0; i < arraysize(fix->reserved); i++)
- fix->reserved[i] = 0;
-
- return 0;
-}
-
-
-/*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- par->xres = var->xres;
- par->yres = var->yres;
- par->xres_vir = var->xres_virtual;
- par->yres_vir = var->yres_virtual;
- par->bpp = var->bits_per_pixel;
- par->pixclock = var->pixclock;
- par->vmode = var->vmode;
-
- par->red = var->red;
- par->green = var->green;
- par->blue = var->blue;
- par->transp = var->transp;
-
- par->left_margin = var->left_margin;
- par->right_margin = var->right_margin;
- par->upper_margin = var->upper_margin;
- par->lower_margin = var->lower_margin;
- par->hsync_len = var->hsync_len;
- par->vsync_len = var->vsync_len;
-
- return 0;
-}
-
-
-/*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- int i;
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres_vir;
- var->yres_virtual = par->yres_vir;
- var->xoffset = 0;
- var->yoffset = 0;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- var->red = par->red;
- var->green = par->green;
- var->blue = par->blue;
- var->transp = par->transp;
-
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
-
- var->accel = FB_ACCEL_RETINAZ3;
-
- var->pixclock = par->pixclock;
-
- var->sync = 0; /* ??? */
- var->left_margin = par->left_margin;
- var->right_margin = par->right_margin;
- var->upper_margin = par->upper_margin;
- var->lower_margin = par->lower_margin;
- var->hsync_len = par->hsync_len;
- var->vsync_len = par->vsync_len;
-
- for (i = 0; i < arraysize(var->reserved); i++)
- var->reserved[i] = 0;
-
- var->vmode = par->vmode;
- return 0;
-}
-
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp)
-{
- /* We'll get to this */
-
- if (regno > 255)
- return 1;
-
- retz3_color_table [regno][0] = red & 0xff;
- retz3_color_table [regno][1] = green & 0xff;
- retz3_color_table [regno][2] = blue & 0xff;
- retz3_color_table [regno][3] = transp;
-
- reg_w(VDAC_ADDRESS_W, regno);
- reg_w(VDAC_DATA, (red & 0xff) >> 2);
- reg_w(VDAC_DATA, (green & 0xff) >> 2);
- reg_w(VDAC_DATA, (blue & 0xff) >> 2);
-
- return 0;
-}
-
-
-/*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp)
-{
- if (regno > 255)
- return 1;
- *red = retz3_color_table [regno][0];
- *green = retz3_color_table [regno][1];
- *blue = retz3_color_table [regno][2];
- *transp = retz3_color_table [regno][3];
- return 0;
-}
-
-
-/*
- * (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
- int i;
-
- if (blank)
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- }
- else
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
- }
-}
-
-
-void retz3_bitblt (struct fb_var_screeninfo *var,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask)
-{
-
- volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
- unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
-
- unsigned short mod;
- unsigned long tmp;
- unsigned long pat, src, dst;
- unsigned char blt_status;
-
- int i, xres_virtual = var->xres_virtual;
- short bpp = (var->bits_per_pixel & 0xff);
-
- if (bpp < 8)
- bpp = 8;
-
- tmp = mask | (mask << 16);
-
-#if 0
- /*
- * Check for blitter finished before we start messing with the
- * pattern.
- */
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }while ((blt_status & 1) == 0);
-#endif
-
- i = 0;
- do{
- *pattern++ = tmp;
- }while(i++ < bpp/4);
-
- tmp = cmd << 8;
- *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
- mod = 0xc0c2;
-
- pat = 8 * PAT_MEM_OFF;
- dst = bpp * (destx + desty * xres_virtual);
-
- /*
- * Source is not set for clear.
- */
- if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
- src = bpp * (srcx + srcy * xres_virtual);
-
- if (destx > srcx) {
- mod &= ~0x8000;
- src += bpp * (width - 1);
- dst += bpp * (width - 1);
- pat += bpp * 2;
- }
- if (desty > srcy) {
- mod &= ~0x4000;
- src += bpp * (height - 1) * xres_virtual;
- dst += bpp * (height - 1) * xres_virtual;
- pat += bpp * 4;
- }
-
- *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
- }
-
- *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
- *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
- tmp = mod << 16;
- *(acm + ACM_CONTROL/4) = tmp;
-
- tmp = width | (height << 16);
-
- *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
- /*
- * No reason to wait for the blitter to finish, it is better
- * just to check if it has finished before we use it again.
- */
-#if 1
-#if 0
- while ((*(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2)) & 1) == 0);
-#else
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }
- while ((blt_status & 1) == 0);
-#endif
-#endif
-}
+#include <linux/init.h>
-#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
- short width, unsigned short height,
- unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
- /* Guess we gotta deal with the cursor at some point */
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
- retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
- retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par)
-{
- if (current_par_valid)
- *par = current_par;
- else
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
-}
-
-
-static void retz3_fb_set_par(struct retz3_fb_par *par)
-{
- current_par = *par;
- current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct retz3_fb_par par;
-
- if ((err = fbhw->decode_var(var, &par)))
- return err;
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3_fb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate = activate;
-
-#if 1
- retz3_set_video(var, &current_par);
-#endif
- return 0;
-}
-
-
-/*
- * Default Colormaps
- */
-
-static unsigned short red16[] =
- { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static unsigned short green16[] =
- { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static unsigned short blue16[] =
- { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
- 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_16_colors =
- { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
- return &default_16_colors;
-}
-
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
- ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return 0;
- hred = CNVT_FROMHW(hred, var->red.length);
- hgreen = CNVT_FROMHW(hgreen, var->green.length);
- hblue = CNVT_FROMHW(hblue, var->blue.length);
- htransp = CNVT_FROMHW(htransp, var->transp.length);
- if (kspc) {
- *red = hred;
- *green = hgreen;
- *blue = hblue;
- if (transp)
- *transp = htransp;
- } else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp)
- put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- }
- return 0;
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (kspc) {
- hred = *red;
- hgreen = *green;
- hblue = *blue;
- htransp = transp ? *transp : 0;
- } else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred = CNVT_TOHW(hred, var->red.length);
- hgreen = CNVT_TOHW(hgreen, var->green.length);
- hblue = CNVT_TOHW(hblue, var->blue.length);
- htransp = CNVT_TOHW(htransp, var->transp.length);
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
- return 0;
- }
- return 0;
-}
-
-
-static void do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
- else
- do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff = 0, fromoff = 0;
-
- if (to->start > from->start)
- fromoff = to->start-from->start;
- else
- tooff = from->start-to->start;
- size = to->len-tooff;
- if (size > from->len-fromoff)
- size = from->len-fromoff;
- if (size < 0)
- return;
- size *= sizeof(unsigned short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff,
- from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
- int size = len*sizeof(unsigned short);
-
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return -1;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return 0;
-}
-
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1)
- retz3_fb_get_par(&par);
- else
- error = fbhw->decode_var(&disp[con].var, &par);
- return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1) {
- retz3_fb_get_par(&par);
- error = fbhw->encode_var(var, &par);
- } else
- *var = disp[con].var;
- return error;
-}
-
-
-static void retz3_fb_set_disp(int con)
-{
- struct fb_fix_screeninfo fix;
-
- retz3_fb_get_fix(&fix, con);
- if (con == -1)
- con = 0;
- disp[con].screen_base = (unsigned char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = z3fb_inverse;
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
- if ((err = do_fb_set_var(var, con == currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = disp[con].var.xres;
- oldyres = disp[con].var.yres;
- oldvxres = disp[con].var.xres_virtual;
- oldvyres = disp[con].var.yres_virtual;
- oldbpp = disp[con].var.bits_per_pixel;
- disp[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- retz3_fb_set_disp(con);
- (*fb_info.changevar)(con);
- alloc_cmap(&disp[con].cmap, 0, 0);
- do_install_cmap(con);
- }
- }
- var->activate = 0;
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console? */
- return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
- else if (disp[con].cmap.len) /* non default colormap? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
-
-/*
- * Set the Colormap
- */
-
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
-
- if (!disp[con].cmap.len) { /* no colormap allocated? */
- if ((err = alloc_cmap(&disp[con].cmap,
- 1<<disp[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console? */
- return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-
-/*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- return -EINVAL;
-}
-
-
-/*
- * RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con)
-{
- return -EINVAL;
-}
-
-
-static struct fb_ops retz3_fb_ops = {
- retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
- retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
-};
-
-
-int retz3_probe(void)
-{
- z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
- return(z3_key);
-}
-
-
-void retz3_video_setup(char *options, int *ints)
-{
- char *this_opt;
- int i;
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")){
- if (!strcmp(this_opt, "inverse")) {
- z3fb_inverse = 1;
- for (i = 0; i < 16; i++) {
- red16[i] = ~red16[i];
- green16[i] = ~green16[i];
- blue16[i] = ~blue16[i];
- }
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else
- z3fb_mode = get_video_mode(this_opt);
- }
-}
-
-
-/*
- * Initialization
- */
-
-struct fb_info *retz3_fb_init(long *mem_start)
-{
- int err;
- struct retz3_fb_par par;
-
- memstart = mem_start;
-
- fbhw = &retz3_switch;
-
- err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
- NUM_TOTAL_MODES, retz3_fb_predefined);
- if (err < 0)
- panic("Cannot register frame buffer\n");
-
- fbhw->init();
-
- if (z3fb_mode == -1)
- z3fb_mode = 1;
-
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
- fbhw->encode_var(&retz3_fb_predefined[0], &par);
-
- strcpy(fb_info.modename, retz3_fb_name);
- fb_info.disp = disp;
- fb_info.switch_con = &z3fb_switch;
- fb_info.updatevar = &z3fb_updatevar;
- fb_info.blank = &z3fb_blank;
- fb_info.setcmap = &z3fb_setcmap;
-
- do_fb_set_var(&retz3_fb_predefined[0], 0);
- retz3_fb_get_var(&disp[0].var, -1);
- retz3_fb_set_disp(-1);
- do_install_cmap(0);
-
- return &fb_info;
-}
-
-
-static int z3fb_switch(int con)
-{
- /* Do we have to save the colormap? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
- do_fb_set_var(&disp[con].var, 1);
- currcon = con;
- /* Install new colormap */
- do_install_cmap(con);
- return 0;
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con)
-{
- return 0;
-}
-
-
-/*
- * Blank the display.
- */
-
-static void z3fb_blank(int blank)
-{
- fbhw->blank(blank);
-}
-
-
-/*
- * Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
- * Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
- int i;
-
- for (i = 1; i <= NUM_PREDEF_MODES; i++)
- if (!strcmp(name, retz3_fb_modenames[i])){
- retz3_fb_predefined[0] = retz3_fb_predefined[i];
- return i;
- }
- return -1;
-}
-/*
- * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- * Geert Uytterhoeven
- * clgen.c: Copyright (C) 1996 Frank Neumann
- *
- * History:
- * - 22 Jan 97: Initial work
- * - 14 Feb 97: Screen initialization works somewhat, still only
- * 8-bit packed pixel is supported.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
-#include <linux/zorro.h>
#include <asm/pgtable.h>
#include "retz3fb.h"
@@ -3402,7 +1652,7 @@ void retz3_video_setup(char *options, int *ints)
* Initialization
*/
-struct fb_info *retz3_fb_init(long *mem_start)
+__initfunc(struct fb_info *retz3_fb_init(long *mem_start))
{
int err;
struct retz3_fb_par par;
diff --git a/arch/m68k/amiga/retz3fb.h b/arch/m68k/amiga/retz3fb.h
index 9ff209060..0cb03c324 100644
--- a/arch/m68k/amiga/retz3fb.h
+++ b/arch/m68k/amiga/retz3fb.h
@@ -284,289 +284,3 @@
#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
#define Z3BLTset 0xf0 /* 1 */
-/*
- * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * History:
- * - 22 Jan 97: Initial work
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(sreg,sdat) \
- do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(creg,cdat) \
- do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(greg,gdat) \
- do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(areg,adat) \
- do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(preg,pdat) \
- do{ reg_w(PLL_IDX, preg); \
- reg_w(PLL_DATA, (pdat & 0xff)); \
- reg_w(PLL_DATA, (pdat >> 8));\
- } while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET 0x00c00000
-#define ACM_OFFSET 0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET 0x00
-#define ACM_SECONDARY_OFFSET 0x04
-#define ACM_MODE_CONTROL 0x08
-#define ACM_CURSOR_POSITION 0x0c
-#define ACM_START_STATUS 0x30
-#define ACM_CONTROL 0x34
-#define ACM_RASTEROP_ROTATION 0x38
-#define ACM_BITMAP_DIMENSION 0x3c
-#define ACM_DESTINATION 0x40
-#define ACM_SOURCE 0x44
-#define ACM_PATTERN 0x48
-#define ACM_FOREGROUND 0x4c
-#define ACM_BACKGROUND 0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX 0x03c4 /* Sequencer Index */
-#define SEQ_DATA 0x03c5
-#define SEQ_RESET 0x00
-#define SEQ_CLOCKING_MODE 0x01
-#define SEQ_MAP_MASK 0x02
-#define SEQ_CHAR_MAP_SELECT 0x03
-#define SEQ_MEMORY_MODE 0x04
-#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */
-#define SEQ_UNKNOWN1 0x06
-#define SEQ_UNKNOWN2 0x07
-#define SEQ_CHIP_ID 0x08
-#define SEQ_UNKNOWN3 0x09
-#define SEQ_CURSOR_COLOR1 0x0a
-#define SEQ_CURSOR_COLOR0 0x0b
-#define SEQ_CURSOR_CONTROL 0x0c
-#define SEQ_CURSOR_X_LOC_HI 0x0d
-#define SEQ_CURSOR_X_LOC_LO 0x0e
-#define SEQ_CURSOR_Y_LOC_HI 0x0f
-#define SEQ_CURSOR_Y_LOC_LO 0x10
-#define SEQ_CURSOR_X_INDEX 0x11
-#define SEQ_CURSOR_Y_INDEX 0x12
-#define SEQ_CURSOR_STORE_HI 0x13
-#define SEQ_CURSOR_STORE_LO 0x14
-#define SEQ_CURSOR_ST_OFF_HI 0x15
-#define SEQ_CURSOR_ST_OFF_LO 0x16
-#define SEQ_CURSOR_PIXELMASK 0x17
-#define SEQ_PRIM_HOST_OFF_HI 0x18
-#define SEQ_PRIM_HOST_OFF_LO 0x19
-#define SEQ_LINEAR_0 0x1a
-#define SEQ_LINEAR_1 0x1b
-#define SEQ_SEC_HOST_OFF_HI 0x1c
-#define SEQ_SEC_HOST_OFF_LO 0x1d
-#define SEQ_EXTENDED_MEM_ENA 0x1e
-#define SEQ_EXT_CLOCK_MODE 0x1f
-#define SEQ_EXT_VIDEO_ADDR 0x20
-#define SEQ_EXT_PIXEL_CNTL 0x21
-#define SEQ_BUS_WIDTH_FEEDB 0x22
-#define SEQ_PERF_SELECT 0x23
-#define SEQ_COLOR_EXP_WFG 0x24
-#define SEQ_COLOR_EXP_WBG 0x25
-#define SEQ_EXT_RW_CONTROL 0x26
-#define SEQ_MISC_FEATURE_SEL 0x27
-#define SEQ_COLOR_KEY_CNTL 0x28
-#define SEQ_COLOR_KEY_MATCH0 0x29
-#define SEQ_COLOR_KEY_MATCH1 0x2a
-#define SEQ_COLOR_KEY_MATCH2 0x2b
-#define SEQ_UNKNOWN6 0x2c
-#define SEQ_CRC_CONTROL 0x2d
-#define SEQ_CRC_DATA_LOW 0x2e
-#define SEQ_CRC_DATA_HIGH 0x2f
-#define SEQ_MEMORY_MAP_CNTL 0x30
-#define SEQ_ACM_APERTURE_1 0x31
-#define SEQ_ACM_APERTURE_2 0x32
-#define SEQ_ACM_APERTURE_3 0x33
-#define SEQ_BIOS_UTILITY_0 0x3e
-#define SEQ_BIOS_UTILITY_1 0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX 0x03ce
-#define GFX_DATA 0x03cf
-#define GFX_SET_RESET 0x00
-#define GFX_ENABLE_SET_RESET 0x01
-#define GFX_COLOR_COMPARE 0x02
-#define GFX_DATA_ROTATE 0x03
-#define GFX_READ_MAP_SELECT 0x04
-#define GFX_GRAPHICS_MODE 0x05
-#define GFX_MISC 0x06
-#define GFX_COLOR_XCARE 0x07
-#define GFX_BITMASK 0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX 0x03d4
-#define CRT_DATA 0x03d5
-#define CRT_HOR_TOTAL 0x00
-#define CRT_HOR_DISP_ENA_END 0x01
-#define CRT_START_HOR_BLANK 0x02
-#define CRT_END_HOR_BLANK 0x03
-#define CRT_START_HOR_RETR 0x04
-#define CRT_END_HOR_RETR 0x05
-#define CRT_VER_TOTAL 0x06
-#define CRT_OVERFLOW 0x07
-#define CRT_PRESET_ROW_SCAN 0x08
-#define CRT_MAX_SCAN_LINE 0x09
-#define CRT_CURSOR_START 0x0a
-#define CRT_CURSOR_END 0x0b
-#define CRT_START_ADDR_HIGH 0x0c
-#define CRT_START_ADDR_LOW 0x0d
-#define CRT_CURSOR_LOC_HIGH 0x0e
-#define CRT_CURSOR_LOC_LOW 0x0f
-#define CRT_START_VER_RETR 0x10
-#define CRT_END_VER_RETR 0x11
-#define CRT_VER_DISP_ENA_END 0x12
-#define CRT_OFFSET 0x13
-#define CRT_UNDERLINE_LOC 0x14
-#define CRT_START_VER_BLANK 0x15
-#define CRT_END_VER_BLANK 0x16
-#define CRT_MODE_CONTROL 0x17
-#define CRT_LINE_COMPARE 0x18
-#define CRT_UNKNOWN1 0x19
-#define CRT_UNKNOWN2 0x1a
-#define CRT_UNKNOWN3 0x1b
-#define CRT_UNKNOWN4 0x1c
-#define CRT_UNKNOWN5 0x1d
-#define CRT_UNKNOWN6 0x1e
-#define CRT_UNKNOWN7 0x1f
-#define CRT_UNKNOWN8 0x20
-#define CRT_UNKNOWN9 0x21
-#define CRT_UNKNOWN10 0x22
-#define CRT_UNKNOWN11 0x23
-#define CRT_UNKNOWN12 0x24
-#define CRT_UNKNOWN13 0x25
-#define CRT_UNKNOWN14 0x26
-#define CRT_UNKNOWN15 0x27
-#define CRT_UNKNOWN16 0x28
-#define CRT_UNKNOWN17 0x29
-#define CRT_UNKNOWN18 0x2a
-#define CRT_UNKNOWN19 0x2b
-#define CRT_UNKNOWN20 0x2c
-#define CRT_UNKNOWN21 0x2d
-#define CRT_UNKNOWN22 0x2e
-#define CRT_UNKNOWN23 0x2f
-#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */
-#define CRT_EXT_START_ADDR 0x31
-#define CRT_EXT_HOR_TIMING2 0x32
-#define CRT_EXT_VER_TIMING 0x33
-#define CRT_MONITOR_POWER 0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R 0x03c2
-#define GREG_STATUS1_R 0x03da
-#define GREG_MISC_OUTPUT_R 0x03cc
-#define GREG_MISC_OUTPUT_W 0x03c2
-#define GREG_FEATURE_CONTROL_R 0x03ca
-#define GREG_FEATURE_CONTROL_W 0x03da
-#define GREG_POS 0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX 0x03C0
-#define ACT_ADDRESS_R 0x03C0
-#define ACT_DATA 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_PALETTE0 0x00
-#define ACT_PALETTE1 0x01
-#define ACT_PALETTE2 0x02
-#define ACT_PALETTE3 0x03
-#define ACT_PALETTE4 0x04
-#define ACT_PALETTE5 0x05
-#define ACT_PALETTE6 0x06
-#define ACT_PALETTE7 0x07
-#define ACT_PALETTE8 0x08
-#define ACT_PALETTE9 0x09
-#define ACT_PALETTE10 0x0A
-#define ACT_PALETTE11 0x0B
-#define ACT_PALETTE12 0x0C
-#define ACT_PALETTE13 0x0D
-#define ACT_PALETTE14 0x0E
-#define ACT_PALETTE15 0x0F
-#define ACT_ATTR_MODE_CNTL 0x10
-#define ACT_OVERSCAN_COLOR 0x11
-#define ACT_COLOR_PLANE_ENA 0x12
-#define ACT_HOR_PEL_PANNING 0x13
-#define ACT_COLOR_SELECT 0x14
-
-/*
- * PLL
- */
-#define PLL_IDX 0x83c8
-#define PLL_DATA 0x83c9
-
-/*
- * Blitter operations
- */
-#define Z3BLTclear 0x00 /* 0 */
-#define Z3BLTand 0x80 /* src AND dst */
-#define Z3BLTandReverse 0x40 /* src AND NOT dst */
-#define Z3BLTcopy 0xc0 /* src */
-#define Z3BLTandInverted 0x20 /* NOT src AND dst */
-#define Z3BLTnoop 0xa0 /* dst */
-#define Z3BLTxor 0x60 /* src XOR dst */
-#define Z3BLTor 0xe0 /* src OR dst */
-#define Z3BLTnor 0x10 /* NOT src AND NOT dst */
-#define Z3BLTequiv 0x90 /* NOT src XOR dst */
-#define Z3BLTinvert 0x50 /* NOT dst */
-#define Z3BLTorReverse 0xd0 /* src OR NOT dst */
-#define Z3BLTcopyInverted 0x30 /* NOT src */
-#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
-#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
-#define Z3BLTset 0xf0 /* 1 */
diff --git a/arch/m68k/amiga/zorro.c b/arch/m68k/amiga/zorro.c
index acca3e6bc..d64ad8ce3 100644
--- a/arch/m68k/amiga/zorro.c
+++ b/arch/m68k/amiga/zorro.c
@@ -13,10 +13,11 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
#include <asm/setup.h>
#include <asm/bitops.h>
#include <asm/amigahw.h>
-#include <linux/zorro.h>
#ifdef CONFIG_ZORRO
@@ -415,10 +416,6 @@ BEGIN_PROD(MASOBOSHI)
PROD("MVD 819", MVD_819)
END
-BEGIN_PROD(DELACOMP)
- PROD("RAM Expansion 2000", DELACOMP_RAM_2000)
-END
-
BEGIN_PROD(VILLAGE_TRONIC)
PROD("Domino Graphics Board (RAM)", DOMINO_RAM)
PROD("Domino Graphics Board (REG)", DOMINO_REG)
@@ -656,7 +653,6 @@ BEGIN_MANUF
MANUF("Helfrich", HELFRICH1)
MANUF("Software Result Enterprises", SW_RESULT_ENTS)
MANUF("Masoboshi", MASOBOSHI)
- MANUF("DelaComp", DELACOMP)
MANUF("Village Tronic", VILLAGE_TRONIC)
MANUF("Utilities Unlimited", UTILITIES_ULTD)
MANUF("Amitrix", AMITRIX)
@@ -992,7 +988,7 @@ static void mark_region(u_long addr, u_long size, int flag)
* Initialization
*/
-void zorro_init(void)
+__initfunc(void zorro_init(void))
{
int i;
struct ConfigDev *cd;
diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c
index 64c9a62d3..efa6fc8b8 100644
--- a/arch/m68k/atari/atafb.c
+++ b/arch/m68k/atari/atafb.c
@@ -46,6 +46,7 @@
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -2911,8 +2912,8 @@ atafb_setcmap(struct fb_cmap *cmap, int con)
return(atari_fb_set_cmap(cmap, 1, con));
}
-struct fb_info *
-atari_fb_init(long *mem_start)
+__initfunc(struct fb_info *
+atari_fb_init(long *mem_start))
{
int err;
int pad;
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b65beefb1..b2887f7da 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -39,6 +39,7 @@
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/kernel_stat.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/traps.h>
@@ -162,15 +163,19 @@ static int free_vme_vec_bitmap = 0;
#define MFP_MK_BASE "0xfa13"
-/* This must agree with head.S. */
-#define ORIG_DO "0x20"
-#define FORMATVEC "0x2E"
-#define SR "0x28"
+/* This must agree with entry.S. */
+#define ORIG_DO "0x24"
+#define FORMATVEC "0x32"
+#define SR "0x2C"
#define SAVE_ALL \
"clrl %%sp@-;" /* stk_adj */ \
"pea -1:w;" /* orig d0 = -1 */ \
"movel %%d0,%%sp@-;" /* d0 */ \
- "moveml %%d1-%%d5/%%a0-%%a1,%%sp@-"
+ "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
+#define GET_CURRENT(tmp) \
+ "movel %%sp,"#tmp";" \
+ "andw #-8192,"#tmp";" \
+ "movel "#tmp",%%a2"
#define BUILD_SLOW_IRQ(n) \
asmlinkage void IRQ_NAME(n); \
@@ -180,6 +185,7 @@ __asm__ (ALIGN_STR "\n" \
SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \
" addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \
SAVE_ALL "\n" \
+ GET_CURRENT(%%d0) "\n" \
" andb #~(1<<(" #n "&7))," /* mask this interrupt */ \
"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \
" bfextu %%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
@@ -282,7 +288,8 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ":
orw #0x700,%%sr /* disable all interrupts */
"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n"
- SAVE_ALL "
+ SAVE_ALL "\n"
+ GET_CURRENT(%%d0) "
/* get vector number from stack frame and convert to source */
bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0
subw #(0x40-8),%%d0
@@ -331,7 +338,7 @@ extern void atari_microwire_cmd( int cmd );
* the atari IRQ handling routines.
*/
-void atari_init_IRQ(void)
+__initfunc(void atari_init_IRQ(void))
{
int i;
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 4f57cb928..beccf9a84 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -22,6 +22,7 @@
#include <linux/timer.h>
#include <linux/kd.h>
#include <linux/random.h>
+#include <linux/init.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
@@ -804,7 +805,7 @@ void atari_kbd_leds (unsigned int leds)
* Martin Rogge, 20 Aug 1995
*/
-int atari_keyb_init(void)
+__initfunc(int atari_keyb_init(void))
{
/* setup key map */
key_maps[0] = ataplain_map;
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 0d0607da0..3cc2a840a 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -32,6 +32,7 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -106,7 +107,7 @@ extern void (*kd_mksound)(unsigned int, unsigned int);
* a temporary VBR and a vector table for the duration of the test.
*/
-static int hwreg_present( volatile void *regp )
+__initfunc(static int hwreg_present( volatile void *regp ))
{
int ret = 0;
long save_sp, save_vbr;
@@ -132,9 +133,8 @@ static int hwreg_present( volatile void *regp )
}
#if 0
-static int hwreg_present_bywrite( volatile void *regp,
- unsigned char val )
-
+__initfunc(static int
+hwreg_present_bywrite(volatile void *regp, unsigned char val))
{
int ret;
long save_sp, save_vbr;
@@ -166,7 +166,7 @@ static int hwreg_present_bywrite( volatile void *regp,
/* Basically the same, but writes a value into a word register, protected
* by a bus error handler */
-static int hwreg_write( volatile void *regp, unsigned short val )
+__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
{
int ret;
long save_sp, save_vbr;
@@ -201,7 +201,7 @@ static int hwreg_write( volatile void *regp, unsigned short val )
* should be readable without trouble (from channel A!).
*/
-static int scc_test( volatile char *ctla )
+__initfunc(static int scc_test( volatile char *ctla ))
{
if (!hwreg_present( ctla ))
return( 0 );
@@ -228,7 +228,7 @@ static int scc_test( volatile char *ctla )
* Parse an Atari-specific record in the bootinfo
*/
-int atari_parse_bootinfo(const struct bi_record *record)
+__initfunc(int atari_parse_bootinfo(const struct bi_record *record))
{
int unknown = 0;
const u_long *data = record->data;
@@ -247,7 +247,7 @@ int atari_parse_bootinfo(const struct bi_record *record)
* Setup the Atari configuration info
*/
-void config_atari(void)
+__initfunc(void config_atari(void))
{
memset(&atari_hw_present, 0, sizeof(atari_hw_present));
@@ -493,7 +493,8 @@ void config_atari(void)
}
}
-static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
+__initfunc(static void
+atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
{
/* set Timer C data Register */
mfp.tim_dt_c = INT_TICKS;
@@ -976,7 +977,7 @@ static void atari_par_console_write (const char *str, unsigned int count)
}
-static void atari_debug_init(void)
+__initfunc(static void atari_debug_init(void))
{
#ifdef CONFIG_KGDB
/* if the m68k_debug_device is used by the GDB stub, do nothing here */
diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c
index de6014171..2e33b151f 100644
--- a/arch/m68k/atari/joystick.c
+++ b/arch/m68k/atari/joystick.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/poll.h>
+#include <linux/init.h>
#include <asm/atarikb.h>
#include <asm/atari_joystick.h>
@@ -128,7 +129,7 @@ struct file_operations atari_joystick_fops = {
release_joystick
};
-int atari_joystick_init(void)
+__initfunc(int atari_joystick_init(void))
{
joystick[0].active = joystick[1].active = 0;
joystick[0].ready = joystick[1].ready = 0;
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index 247b9f684..9dc82de18 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -32,6 +32,8 @@
#include <linux/types.h>
#include <linux/genhd.h>
#include <linux/sched.h>
+#include <linux/init.h>
+
#include <asm/atari_stdma.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
@@ -171,7 +173,7 @@ int stdma_islocked(void)
*
*/
-void stdma_init(void)
+__initfunc(void stdma_init(void))
{
stdma_isr = NULL;
request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 565b20535..4e5f57bc9 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -149,6 +149,7 @@ atari_stram_free (void *ptr)
#else
#include <linux/mm.h>
+#include <linux/init.h>
/* ++roman:
*
@@ -190,7 +191,7 @@ static unsigned long stram_end;
/* Overall end of ST-Ram */
-void atari_stram_init( void )
+__initfunc(void atari_stram_init( void ))
{ int i;
diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
index d35966686..23b7fa9d0 100644
--- a/arch/m68k/boot/amiga/linuxboot.c
+++ b/arch/m68k/boot/amiga/linuxboot.c
@@ -22,6 +22,8 @@
* for more details.
*
* History:
+ * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
+ * interface version 1.0 (Geert)
* 03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
* code for ataboot)
* 30 Dec 1996 Reverted the CPU detection to the old scheme
@@ -791,6 +793,7 @@ static u_long get_chipset(void)
static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
{
*cpu = *fpu = 0;
+
if (SysBase->AttnFlags & AFF_68060)
*cpu = CPU_68060;
else if (SysBase->AttnFlags & AFF_68040)
@@ -799,15 +802,15 @@ static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
*cpu = CPU_68030;
else if (SysBase->AttnFlags & AFF_68020)
*cpu = CPU_68020;
+
if (*cpu == CPU_68040 || *cpu == CPU_68060) {
if (SysBase->AttnFlags & AFF_FPU40)
*fpu = *cpu;
- } else {
- if (SysBase->AttnFlags & AFF_68882)
- *fpu = FPU_68882;
- else if (SysBase->AttnFlags & AFF_68881)
- *fpu = FPU_68881;
- }
+ } else if (SysBase->AttnFlags & AFF_68882)
+ *fpu = FPU_68882;
+ else if (SysBase->AttnFlags & AFF_68881)
+ *fpu = FPU_68881;
+
*mmu = *cpu;
}
@@ -1047,7 +1050,7 @@ static int create_compat_bootinfo(void)
compat_bootinfo.cputype |= COMPAT_FPU_68040;
else if (bi.fputype & FPU_68060)
compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else {
+ else if (bi.fputype) {
Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
return(0);
}
diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
index 8ebfe63b4..e04425a3a 100644
--- a/arch/m68k/boot/amiga/linuxboot.h
+++ b/arch/m68k/boot/amiga/linuxboot.h
@@ -31,7 +31,7 @@
* Amiboot Version
*/
-#define AMIBOOT_VERSION "5.4"
+#define AMIBOOT_VERSION "5.5"
/*
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 5768516bd..466cf3fbc 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -51,13 +51,23 @@
.include "fpsp.h"
-LOFF_ORIG_D0 = 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0 = 0x24
+
+#define curptr a2
#define SAVE_ALL \
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
|xref b1238_fix
@@ -81,6 +91,7 @@ real_dz:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -175,6 +186,7 @@ inex_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -204,6 +216,7 @@ ovfl_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -233,6 +246,7 @@ unfl_done:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -258,6 +272,7 @@ real_snan:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -283,6 +298,7 @@ real_operr:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -314,6 +330,7 @@ real_bsun:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -338,6 +355,7 @@ real_fline:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -363,6 +381,7 @@ real_unsupp:
movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -419,6 +438,7 @@ Lmustsched:
SAVE_ALL
moveq #-1,%d0
movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
+ GET_CURRENT(%d0)
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
@@ -497,7 +517,7 @@ user_read:
movel %d0,-(%sp)
movel %a1,-(%sp)
movel %a0,-(%sp)
- jsr copyin
+ jsr copyin
addw #12,%sp
movel (%sp)+,%d1
rts
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index 5940a374a..3c310c237 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -36,13 +36,23 @@
#include <linux/linkage.h>
-LOFF_ORIG_D0 = 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0 = 0x24
+
+#define curptr a2
#define SAVE_ALL \
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
|################################
| (1) EXAMPLE CALL-OUTS #
@@ -85,6 +95,7 @@ Lmustsched:
SAVE_ALL
moveq #-1,%d0
movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
+ GET_CURRENT(%d0)
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
|
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 2cb35e67f..ef5ef46d6 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -33,12 +33,13 @@
* 10(sp) - d5
* 14(sp) - a0
* 18(sp) - a1
- * 1C(sp) - d0
- * 20(sp) - orig_d0
- * 24(sp) - stack adjustment
- * 28(sp) - sr
- * 2A(sp) - pc
- * 2E(sp) - format & vector
+ * 1C(sp) - a2
+ * 20(sp) - d0
+ * 24(sp) - orig_d0
+ * 28(sp) - stack adjustment
+ * 2C(sp) - sr
+ * 2E(sp) - pc
+ * 32(sp) - format & vector
*/
/*
@@ -47,6 +48,11 @@
* number 0 in the 'current_set' list.
*/
+/*
+ * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
+ * the whole kernel.
+ */
+
#include <linux/sys.h>
#include <linux/config.h>
#include <linux/linkage.h>
@@ -57,6 +63,8 @@
.globl SYMBOL_NAME(kgdb_registers)
#endif
+#define curptr a2
+
LENOSYS = 38
/*
@@ -80,15 +88,15 @@ LTASK_FLAGS = 20
#define MAX_NOINT_IPL 0
#endif /* machine compilation types */
-LD0 = 0x1C
-LORIG_D0 = 0x20
-LSR = 0x28
-LFORMATVEC = 0x2E
+LD0 = 0x20
+LORIG_D0 = 0x24
+LSR = 0x2C
+LFORMATVEC = 0x32
/*
* This defines the normal kernel pt-regs layout.
*
- * regs are a2-a6 and d6-d7 preserved by C code
+ * regs a3-a6 and d6-d7 are preserved by C code
* the kernel doesn't mess with usp unless it needs to
*/
#ifndef CONFIG_KGDB
@@ -96,7 +104,7 @@ LFORMATVEC = 0x2E
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
#else
/* Need to save the "missing" registers for kgdb...
*/
@@ -104,25 +112,30 @@ LFORMATVEC = 0x2E
clrl %sp@-; /* stk_adj */ \
movel %d0,%sp@-; /* orig d0 */ \
movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1,%sp@-; \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \
moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \
- moveml %a2-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A2
+ moveml %a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3;
#endif
#define RESTORE_ALL \
- moveml %sp@+,%a0-%a1/%d1-%d5; \
+ moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \
movel %sp@+,%d0; \
addql #4,%sp; /* orig d0 */ \
addl %sp@+,%sp; /* stk adj */ \
rte
-#define SWITCH_STACK_SIZE (7*4+4) /* includes return address */
+#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
#define SAVE_SWITCH_STACK \
- moveml %a2-%a6/%d6-%d7,%sp@-
+ moveml %a3-%a6/%d6-%d7,%sp@-
#define RESTORE_SWITCH_STACK \
- moveml %sp@+,%a2-%a6/%d6-%d7
+ moveml %sp@+,%a3-%a6/%d6-%d7
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
@@ -139,6 +152,7 @@ ENTRY(buserr)
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(buserr_c)
addql #4,%sp
@@ -150,6 +164,7 @@ ENTRY(trap)
movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
addql #4,%sp
@@ -190,6 +205,7 @@ ENTRY(system_call)
SAVE_ALL
movel %d0,%d2
+ GET_CURRENT(%d0)
| save top of frame
pea %sp@
jbsr SYMBOL_NAME(set_esp0)
@@ -197,8 +213,7 @@ ENTRY(system_call)
cmpl #NR_syscalls,%d2
jcc badsys
- movel SYMBOL_NAME(current_set),%a0
- btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS
+ btst #5,%curptr@(LTASK_FLAGS+3) | PF_TRACESYS
jne do_trace
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
movel %d0,%sp@(LD0) | save the return value
@@ -208,24 +223,23 @@ SYMBOL_NAME_LABEL(ret_from_exception)
bnes 2f | if so, skip resched, signals
tstl SYMBOL_NAME(need_resched)
jne SYMBOL_NAME(reschedule)
- movel SYMBOL_NAME(current_set),%a0
- cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals
+ cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
- bclr #5,%a0@(LTASK_FLAGS+1) | check for delayed trace
+ bclr #5,%curptr@(LTASK_FLAGS+1) | check for delayed trace
jne do_delayed_trace
5:
- tstl %a0@(LTASK_STATE) | state
+ tstl %curptr@(LTASK_STATE) | state
jne SYMBOL_NAME(reschedule)
- tstl %a0@(LTASK_COUNTER) | counter
+ tstl %curptr@(LTASK_COUNTER) | counter
jeq SYMBOL_NAME(reschedule)
- movel %a0@(LTASK_BLOCKED),%d0
+ movel %curptr@(LTASK_BLOCKED),%d0
movel %d0,%d1 | save blocked in d1 for sig handling
notl %d0
- btst #4,%a0@(LTASK_FLAGS+3) | PF_PTRACED
+ btst #4,%curptr@(LTASK_FLAGS+3) | PF_PTRACED
jeq 1f
moveq #-1,%d0 | let the debugger see all signals
-1: andl %a0@(LTASK_SIGNAL),%d0
+1: andl %curptr@(LTASK_SIGNAL),%d0
jne Lsignal_return
2: RESTORE_ALL
@@ -248,7 +262,6 @@ do_delayed_trace:
jbsr SYMBOL_NAME(send_sig)
addql #8,%sp
addql #4,%sp
- movel SYMBOL_NAME(current_set),%a0
jra 5b
/*
@@ -260,6 +273,7 @@ SYMBOL_NAME_LABEL(inthandler)
movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
| signifies that the stack frame
| is NOT for syscall
+ GET_CURRENT(%d0)
addql #1,SYMBOL_NAME(local_irq_count)
| put exception # in d0
bfextu %sp@(LFORMATVEC){#4,#10},%d0
@@ -270,28 +284,31 @@ SYMBOL_NAME_LABEL(inthandler)
addql #8,%sp | pop parameters off stack
SYMBOL_NAME_LABEL(ret_from_interrupt)
- /* check if we need to do software interrupts */
- movel SYMBOL_NAME(local_irq_count),%d1
- subql #1,%d1
- jne 4f
-#if 0
- bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt.
+ subql #1,SYMBOL_NAME(local_irq_count)
+ jeq 1f
+2:
+ RESTORE_ALL
+1:
+#if 1
+ bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt.
#if MAX_NOINT_IPL > 0
cmpiw #MAX_NOINT_IPL,%d0
#endif
- jhi 4f
+ jhi 2b
#endif
+ /* Let the rest run with interrupts allowed. This is safe since
+ the kernel never uses a non-standard ipl and this is the outer
+ level interrupt. */
+ andw #ALLOWINT,%sr
+
+ /* check if we need to do software interrupts */
+
movel SYMBOL_NAME(bh_active),%d0
andl SYMBOL_NAME(bh_mask),%d0
- jeq 3f
+ jeq SYMBOL_NAME(ret_from_exception)
- jbsr SYMBOL_NAME(do_bottom_half)
-3:
- clrl SYMBOL_NAME(local_irq_count)
- jra SYMBOL_NAME(ret_from_exception)
-4:
- movel %d1,SYMBOL_NAME(local_irq_count)
- RESTORE_ALL
+ pea SYMBOL_NAME(ret_from_exception)
+ jra SYMBOL_NAME(do_bottom_half)
/* Handler for uninitialized and spurious interrupts */
@@ -398,7 +415,7 @@ SYMBOL_NAME_LABEL(resume)
3:
/* get pointer to tss struct (a1 contains new task) */
- movel %a1,SYMBOL_NAME(current_set)
+ movel %a1,%curptr
addl %d1,%a1
/* Skip address space switching if they are the same. */
@@ -419,7 +436,7 @@ SYMBOL_NAME_LABEL(resume)
movec %cacr,%d0
oriw #LFLUSH_I_AND_D,%d0
movec %d0,%cacr
-
+
/* switch the root pointer */
pmove %a1@(LTSS_CRP),%crp
#endif
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index c2b72aa2d..36a4072ac 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -223,17 +223,9 @@ ENTRY(_start)
movel %d0,%a0@ /* save cache mode for page tables */
/*
- * raise interrupt level with MASTER bit set, copy isp to msp (if not 68060)
+ * raise interrupt level
*/
-#ifdef FROM_PL9
- movew #0x3700,%sr
- is_060(1f)
- movec %isp,%d0
- movel %d0,%sp
-1:
-#else
movew #0x2700,%sr
-#endif
/*
If running on an Atari, determine the I/O base of the
@@ -896,8 +888,10 @@ Lcache68060:
/*
* Setup initial stack pointer
+ * We need to get current loaded up with our first task...
*/
- lea SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp
+ lea SYMBOL_NAME(init_task_union),%a2
+ lea 8192(%a2),%sp
/* jump to the kernel start */
putr()
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index f49c38cd3..39e1fbce6 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -29,6 +29,7 @@
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -79,7 +80,7 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
* the IRQ handling routines.
*/
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 3138d99df..f6bb0689b 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -6,6 +6,8 @@
#include <linux/mm.h>
#include <linux/user.h>
#include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/machdep.h>
@@ -14,6 +16,7 @@
#include <asm/semaphore.h>
#include <asm/checksum.h>
#include <asm/hardirq.h>
+#include <asm/softirq.h>
asmlinkage long long __ashrdi3 (long long, int);
extern char m68k_debug_device[];
@@ -40,6 +43,7 @@ EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(__m68k_bh_counter);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 5422831a8..ad0662f22 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -10,6 +10,7 @@
* This file handles the architecture-dependent parts of process handling..
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -29,6 +30,23 @@
#include <asm/traps.h>
#include <asm/machdep.h>
#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+union task_union init_task_union
+ __attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
+ = { task: INIT_TASK };
asmlinkage void ret_from_exception(void);
@@ -46,8 +64,17 @@ asmlinkage int sys_idle(void)
/* endless idle loop with no priority at all */
current->priority = -100;
current->counter = -100;
- for (;;)
+ for (;;){
+ if (!need_resched)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+ /* block out HSYNC on the atari (falcon) */
+ __asm__("stop #0x2200" : : : "cc");
+#else /* portable version */
+ __asm__("stop #0x2000" : : : "cc");
+#endif /* machine compilation types */
+ run_task_queue(&tq_scheduler);
schedule();
+ }
ret = 0;
out:
unlock_kernel();
@@ -76,8 +103,8 @@ void show_regs(struct pt_regs * regs)
printk("\n");
printk("Format %02x Vector: %04x PC: %08lx Status: %04x\n",
regs->format, regs->vector, regs->pc, regs->sr);
- printk("ORIG_D0: %08lx D0: %08lx A1: %08lx\n",
- regs->orig_d0, regs->d0, regs->a1);
+ printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
+ regs->orig_d0, regs->d0, regs->a2, regs->a1);
printk("A0: %08lx D5: %08lx D4: %08lx\n",
regs->a0, regs->d5, regs->d4);
printk("D3: %08lx D2: %08lx D1: %08lx\n",
@@ -144,8 +171,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct switch_stack * childstack, *stack;
unsigned long stack_offset, *retp;
- stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
- childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+ stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs);
+ childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
*childregs = *regs;
childregs->d0 = 0;
@@ -231,7 +258,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->regs.d7 = sw->d7;
dump->regs.a0 = regs->a0;
dump->regs.a1 = regs->a1;
- dump->regs.a2 = sw->a2;
+ dump->regs.a2 = regs->a2;
dump->regs.a3 = sw->a3;
dump->regs.a4 = sw->a4;
dump->regs.a5 = sw->a5;
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 70e341b31..be4149cbb 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -47,23 +47,11 @@
static int regoff[] = {
PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
- PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4),
+ PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
};
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -116,7 +104,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -126,7 +114,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -137,7 +125,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -168,7 +156,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -178,7 +166,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -189,12 +177,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 2);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -340,7 +328,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index dfd91d0d4..def50a747 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -18,6 +18,7 @@
#include <linux/genhd.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -55,13 +56,13 @@ static struct mem_info m68k_ramdisk = { 0, 0 };
static char m68k_command_line[CL_SIZE];
char saved_command_line[CL_SIZE];
-void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
/* machine dependent keyboard functions */
-int (*mach_keyb_init) (void);
+int (*mach_keyb_init) (void) __initdata;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
/* machine dependent irq functions */
-void (*mach_init_IRQ) (void);
+void (*mach_init_IRQ) (void) __initdata;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
void (*mach_get_model) (char *model) = NULL;
int (*mach_get_hardware_list) (char *buffer) = NULL;
@@ -73,12 +74,12 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
int (*mach_set_clock_mmss) (unsigned long) = NULL;
void (*mach_reset)( void );
-struct fb_info *(*mach_fb_init)(long *);
+struct fb_info *(*mach_fb_init)(long *) __initdata;
long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_video_setup) (char *, int *);
+void (*mach_video_setup) (char *, int *) __initdata;
#ifdef CONFIG_BLK_DEV_FD
-int (*mach_floppy_init) (void) = NULL;
-void (*mach_floppy_setup) (char *, int *) = NULL;
+int (*mach_floppy_init) (void) __initdata = NULL;
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
void (*mach_floppy_eject) (void) = NULL;
#endif
@@ -94,7 +95,7 @@ extern void config_apollo(void);
#define MASK_256K 0xfffc0000
-static void m68k_parse_bootinfo(const struct bi_record *record)
+__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
{
while (record->tag != BI_LAST) {
int unknown = 0;
@@ -141,8 +142,8 @@ static void m68k_parse_bootinfo(const struct bi_record *record)
}
}
-void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p)
+ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
{
unsigned long memory_start, memory_end;
extern int _etext, _edata, _end;
@@ -337,7 +338,7 @@ int get_hardware_list(char *buffer)
}
#ifdef CONFIG_BLK_DEV_FD
-int floppy_init(void)
+__initfunc(int floppy_init(void))
{
if (mach_floppy_init)
return mach_floppy_init();
@@ -345,7 +346,7 @@ int floppy_init(void)
return 0;
}
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
{
if (mach_floppy_setup)
mach_floppy_setup (str, ints);
@@ -358,7 +359,7 @@ void floppy_eject(void)
}
#endif
-unsigned long arch_kbd_init(void)
+__initfunc(unsigned long arch_kbd_init(void))
{
return mach_keyb_init();
}
@@ -372,7 +373,7 @@ void arch_gettod(int *year, int *mon, int *day, int *hour,
*year = *mon = *day = *hour = *min = *sec = 0;
}
-void video_setup (char *options, int *ints)
+__initfunc(void video_setup (char *options, int *ints))
{
if (mach_video_setup)
mach_video_setup (options, ints);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index c60e82b0b..52c13445d 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -42,7 +42,9 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
const int frame_extra_sizes[16] = {
@@ -466,7 +468,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
if (signr != SIGCHLD)
continue;
/* check for SIGCHLD: it's special */
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
/* nothing */;
continue;
}
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 5acfd1cbd..e29509cac 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -532,12 +532,15 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
*/
vma = find_vma (current->mm, addr);
ret = -EINVAL;
+ /* Check for overflow. */
+ if (addr + len < addr)
+ goto out;
if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
goto out;
}
if (CPU_IS_020_OR_030) {
- if (scope == FLUSH_SCOPE_LINE) {
+ if (scope == FLUSH_SCOPE_LINE && len < 256) {
unsigned long cacr;
__asm__ ("movec %%cacr, %0" : "=r" (cacr));
if (cache & FLUSH_CACHE_INSN)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index dbff49276..7b3acdfa6 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -27,6 +27,24 @@ static inline int set_rtc_mmss(unsigned long nowtime)
return -1;
}
+static inline void do_profile (unsigned long pc)
+{
+ if (prof_buffer && current->pid) {
+ extern int _stext;
+ pc -= (unsigned long) &_stext;
+ pc >>= prof_shift;
+ if (pc < prof_len)
+ ++prof_buffer[pc];
+ else
+ /*
+ * Dont ignore out-of-bounds PC values silently,
+ * put them into the last histogram slot, so if
+ * present, they will show up as a sharp peak.
+ */
+ ++prof_buffer[prof_len-1];
+ }
+}
+
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
@@ -38,6 +56,9 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
do_timer(regs);
+ if (!user_mode(regs))
+ do_profile(regs->pc);
+
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 1cc547907..25be40007 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -27,6 +27,7 @@
#include <linux/user.h>
#include <linux/string.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/fpu.h>
@@ -63,7 +64,7 @@ asm(".text\n"
__ALIGN_STR "\n"
SYMBOL_NAME_STR(nmihandler) ": rte");
-void trap_init (void)
+__initfunc(void trap_init (void))
{
int i;
@@ -932,16 +933,15 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
#endif
console_verbose();
printk("%s: %08x\n",str,nr);
- printk("PC: [<%08lx>]\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
+ printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
+ fp->pc, fp->sr, fp, fp->a2);
printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
fp->d0, fp->d1, fp->d2, fp->d3);
printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
fp->d4, fp->d5, fp->a0, fp->a1);
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, stackpage=%08lx)\n",
- current->comm, current->pid, current->kernel_stack_page);
+ current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
#ifdef CONFIG_KGDB
}
#endif
diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S
index 76ffc3cc5..8e4141149 100644
--- a/arch/m68k/lib/semaphore.S
+++ b/arch/m68k/lib/semaphore.S
@@ -19,8 +19,7 @@ ENTRY(__down_failed)
movel %a1,-(%sp)
jbsr SYMBOL_NAME(__down)
movel (%sp)+,%a1
- movel (%sp)+,%d0
- movel (%sp)+,%d1
+ moveml (%sp)+,%a0/%d0/%d1
rts
ENTRY(__down_failed_interruptible)
@@ -30,6 +29,7 @@ ENTRY(__down_failed_interruptible)
jbsr SYMBOL_NAME(__down_interruptible)
movel (%sp)+,%a1
movel (%sp)+,%d1
+ movel (%sp)+,%a0
rts
ENTRY(__up_wakeup)
@@ -37,6 +37,5 @@ ENTRY(__up_wakeup)
movel %a1,-(%sp)
jbsr SYMBOL_NAME(__up)
movel (%sp)+,%a1
- movel (%sp)+,%d0
- movel (%sp)+,%d1
+ moveml (%sp)+,%a0/%d0/%d1
rts
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 71b46e2d9..193c6baee 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -32,14 +32,10 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
- void (*handler)(struct task_struct *,
- struct vm_area_struct *,
- unsigned long,
- int);
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
struct vm_area_struct * vma;
- unsigned long fixup, fault_pc;
+ unsigned long fixup;
int write;
#ifdef DEBUG
@@ -73,10 +69,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
*/
good_area:
write = 0;
- handler = do_no_page;
switch (error_code & 3) {
default: /* 3: write, present */
- handler = do_wp_page;
/* fall through */
case 2: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
@@ -89,7 +83,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handler(tsk, vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
/* There seems to be a missing invalidate somewhere in do_no_page.
@@ -108,10 +102,10 @@ bad_area:
up(&mm->mmap_sem);
/* Are we prepared to handle this fault? */
- fault_pc = regs->pc;
- if ((fixup = search_exception_table(fault_pc)) != 0) {
+ if ((fixup = search_exception_table(regs->pc)) != 0) {
struct pt_regs *tregs;
- printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", fault_pc, fixup);
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+ current->comm, regs->pc, fixup);
/* Create a new four word stack frame, discarding the old
one. */
regs->stkadj = frame_extra_sizes[regs->format];
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 01cd315dd..b46037f80 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/init.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif
@@ -116,9 +117,8 @@ pte_t *kernel_page_table (unsigned long *memavailp)
return ptablep;
}
-static unsigned long map_chunk (unsigned long addr,
- unsigned long size,
- unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
{
#define ONEMEG (1024*1024)
#define L3TREESIZE (256*1024)
@@ -283,6 +283,11 @@ static unsigned long map_chunk (unsigned long addr,
extern unsigned long free_area_init(unsigned long, unsigned long);
+/* References to section boundaries */
+
+extern char _text, _etext, _edata, __bss_start, _end;
+extern char __init_begin, __init_end;
+
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
/*
@@ -291,7 +296,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* The parameters are pointers to where to stick the starting and ending
* addresses of available kernel virtual memory.
*/
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
{
int chunk;
unsigned long mem_avail = 0;
@@ -395,12 +400,12 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
return PAGE_ALIGN(free_area_init (start_mem, end_mem));
}
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
int codepages = 0;
int datapages = 0;
+ int initpages = 0;
unsigned long tmp;
- extern int _etext;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
@@ -448,8 +453,15 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
if (VTOP (tmp) >= mach_max_dma_address)
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
if (PageReserved(mem_map+MAP_NR(tmp))) {
- if (tmp < (unsigned long)&_etext)
- codepages++;
+ if (tmp >= (unsigned long)&_text
+ && tmp < (unsigned long)&_edata) {
+ if (tmp < (unsigned long) &_etext)
+ codepages++;
+ else
+ datapages++;
+ } else if (tmp >= (unsigned long) &__init_begin
+ && tmp < (unsigned long) &__init_end)
+ initpages++;
else
datapages++;
continue;
@@ -461,16 +473,24 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
#endif
free_page(tmp);
}
- printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10));
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10));
}
void free_initmem(void)
{
- /* To be written */
+ unsigned long addr;
+
+ addr = (unsigned long)&__init_begin;
+ for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ free_page(addr);
+ }
}
void si_meminfo(struct sysinfo *val)
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 55d5e98f3..77eb2dbfe 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -280,6 +280,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
return( (vaddr & mask) == (base & mask) );
}
+static unsigned long mm_vtop_fallback (unsigned long);
+
/*
* The following two routines map from a physical address to a kernel
* virtual address and vice versa.
@@ -301,7 +303,13 @@ unsigned long mm_vtop (unsigned long vaddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
+ return mm_vtop_fallback(vaddr);
+}
+/* Separate function to make the common case faster (needs to save less
+ registers) */
+static unsigned long mm_vtop_fallback (unsigned long vaddr)
+{
/* not in one of the memory chunks; test for applying transparent
* translation */
diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds
new file mode 100644
index 000000000..cc5b1e20e
--- /dev/null
+++ b/arch/m68k/vmlinux.lds
@@ -0,0 +1,60 @@
+/* ld script to make m68k Linux kernel */
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x1000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.text.lock) /* out-of-line lock text */
+ *(.gnu.warning)
+ } = 0x4e75
+ .rodata : { *(.rodata) }
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .; /* End of text section */
+
+ .data : { /* Data */
+ *(.data)
+ CONSTRUCTORS
+ }
+
+ . = ALIGN(8192);
+ init_task : { *(init_task) } /* The initial task and kernel stack */
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ _end = . ;
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+}
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 5ea699450..1aa371ae1 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -156,9 +156,9 @@ endif
# The pipe options is bad for my low-mem machine
# Uncomment this if you want this.
#
-#CFLAGS += -pipe
+CFLAGS += -pipe
-HEAD := arch/mips/kernel/head.o
+HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools)
CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES)
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index fd445c865..dd834efd9 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -34,7 +34,11 @@ mkboot: mkboot.c
$(HOSTCC) -o $@ $^
zdisk: zImage
- mcopy -o zImage a:vmlinux
+ if [ -f /etc/remote-mcopy ]; then \
+ ssh rio mcopy -o - a:vmlinux <zImage; \
+ else \
+ mcopy -o zImage a:vmlinux; \
+ fi
dep:
$(CPP) -M *.[cS] > .depend
diff --git a/arch/mips/boot/mkboot.c b/arch/mips/boot/mkboot.c
index 48f27113e..35612d248 100644
--- a/arch/mips/boot/mkboot.c
+++ b/arch/mips/boot/mkboot.c
@@ -355,7 +355,7 @@ main(argc, argv)
char *infile, *outfile;
struct stat ifstat;
off_t ifsize;
- void *image;
+ char *image;
int ifd, ofd, i, symtabix, strtabix;
Elf32_Ehdr eh;
Elf32_Phdr *ph;
@@ -421,7 +421,7 @@ main(argc, argv)
* we're reading might have different type sizes, byteorder
* or alignment than the host.
*/
- memcpy(eh.e_ident, image, sizeof(eh.e_ident));
+ memcpy(eh.e_ident, (void *)image, sizeof(eh.e_ident));
if(memcmp(eh.e_ident, ELFMAG, SELFMAG)) {
fprintf(stderr, "Input file isn't a ELF file\n");
exit(1);
@@ -476,7 +476,7 @@ main(argc, argv)
exit(1);
}
for(i = 0;i < eh.e_phnum; i++)
- get_elfph(image + eh.e_phoff + i * 32, ph + i);
+ get_elfph((void *)(image + eh.e_phoff + i * 32), ph + i);
/*
* ... and then the section headers.
@@ -487,7 +487,7 @@ main(argc, argv)
exit(1);
}
for(i = 0;i < eh.e_shnum; i++)
- get_elfsh(image + eh.e_shoff + (i * 40), sh + i);
+ get_elfsh((void *)(image + eh.e_shoff + (i * 40)), sh + i);
/*
* Find the symboltable and the stringtable in the file.
diff --git a/arch/mips/config.in b/arch/mips/config.in
index a0e655ea1..14e9dec3f 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -178,23 +178,27 @@ fi
source fs/Config.in
if [ "$CONFIG_SGI" != "y" ]; then
- source drivers/char/Config.in
+ source drivers/char/Config.in
- mainmenu_option next_comment
- comment 'Sound'
+ mainmenu_option next_comment
+ comment 'Sound'
- tristate 'Sound card support' CONFIG_SOUND
- if [ "$CONFIG_SOUND" != "n" ]; then
- source drivers/sound/Config.in
- fi
- endmenu
+ tristate 'Sound card support' CONFIG_SOUND
+ if [ "$CONFIG_SOUND" != "n" ]; then
+ source drivers/sound/Config.in
+ fi
+ endmenu
else
- comment 'SGI Character Devices'
- tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
- bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL
- if [ "$CONFIG_SGI_SERIAL" != "n" ]; then
- define_bool CONFIG_SERIAL y
- fi
+ comment 'SGI Character Devices'
+ bool 'Virtual terminal' CONFIG_VT
+ if [ "$CONFIG_VT" = "y" ]; then
+ bool 'Console on virtual terminal' CONFIG_VT_CONSOLE
+ fi
+ tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+ bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL
+ if [ "$CONFIG_SGI_SERIAL" != "n" ]; then
+ define_bool CONFIG_SERIAL y
+ fi
fi
mainmenu_option next_comment
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index dc28a8cd8..33f54a301 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -22,6 +22,7 @@ CONFIG_PCI=y
#
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
CONFIG_CPU_R4X00=y
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R8000 is not set
diff --git a/arch/mips/deskstation/io.c b/arch/mips/deskstation/io.c
new file mode 100644
index 000000000..cd33e2eb6
--- /dev/null
+++ b/arch/mips/deskstation/io.c
@@ -0,0 +1,68 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Low level I/O functions for Jazz family machine.
+ *
+ * FIXME: This implementation fits the Tyne. How does the EISA rPC44 handle
+ * the eight high address bits?
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/sni.h>
+
+/*
+ * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
+ * for the processor.
+ */
+extern unsigned long isa_slot_offset;
+
+static unsigned char deskstation_readb(unsigned long addr)
+{
+ return *(volatile unsigned char *) (isa_slot_offset + addr);
+}
+
+static unsigned short deskstation_readw(unsigned long addr)
+{
+ return *(volatile unsigned short *) (isa_slot_offset + addr);
+}
+
+static unsigned int deskstation_readl(unsigned long addr)
+{
+ return *(volatile unsigned int *) (isa_slot_offset + addr);
+}
+
+static void deskstation_writeb(unsigned char val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_writew(unsigned short val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_writel(unsigned int val, unsigned long addr)
+{
+ *(volatile unsigned char *) (isa_slot_offset + addr) = val;
+}
+
+static void deskstation_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ addr += isa_slot_offset;
+ memset((void *)addr, val, len);
+}
+
+static void deskstation_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ from += isa_slot_offset;
+ memcpy((void *)to, (void *)from, len);
+}
+
+static void deskstation_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ to += isa_slot_offset;
+ memcpy((void *)to, (void *)from, len);
+}
diff --git a/arch/mips/deskstation/setup.c b/arch/mips/deskstation/setup.c
index c2451e855..8b70a656c 100644
--- a/arch/mips/deskstation/setup.c
+++ b/arch/mips/deskstation/setup.c
@@ -5,10 +5,10 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
-#include <asm/ptrace.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -16,6 +16,7 @@
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/ptrace.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/vector.h>
@@ -43,8 +44,7 @@ extern void deskstation_machine_power_off(void);
unsigned long mips_dma_cache_size = 0;
unsigned long mips_dma_cache_base = KSEG0;
-static void
-tyne_irq_setup(void)
+__initfunc(static void tyne_irq_setup(void))
{
set_except_vector(0, deskstation_handle_int);
/* set the clock to 100 Hz */
@@ -58,8 +58,7 @@ tyne_irq_setup(void)
#endif
#ifdef CONFIG_DESKSTATION_RPC44
-static void
-rpc44_irq_setup(void)
+__initfunc(static void rpc44_irq_setup(void))
{
/*
* For the moment just steal the TYNE support. In the
@@ -77,8 +76,7 @@ rpc44_irq_setup(void)
}
#endif
-void
-deskstation_setup(void)
+__initfunc(void deskstation_setup(void))
{
switch(mips_machtype) {
#ifdef CONFIG_DESKSTATION_TYNE
diff --git a/arch/mips/jazz/.cvsignore b/arch/mips/jazz/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/arch/mips/jazz/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/arch/mips/jazz/io.c b/arch/mips/jazz/io.c
new file mode 100644
index 000000000..a151b99fe
--- /dev/null
+++ b/arch/mips/jazz/io.c
@@ -0,0 +1,136 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Low level I/O functions for Jazz family machines.
+ *
+ * Copyright (C) 1997 by Ralf Baechle.
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+#include <asm/jazz.h>
+
+/*
+ * Map an 16mb segment of the EISA address space to 0xe3000000;
+ */
+static inline void map_eisa_address(unsigned long address)
+{
+ /* XXX */
+ /* We've got an wired entry in the TLB. We just need to modify it.
+ fast and clean. But since we want to get rid of wired entries
+ things are a little bit more complicated ... */
+}
+
+static unsigned char jazz_readb(unsigned long addr)
+{
+ unsigned char res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static unsigned short jazz_readw(unsigned long addr)
+{
+ unsigned short res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static unsigned int jazz_readl(unsigned long addr)
+{
+ unsigned int res;
+
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr);
+
+ return res;
+}
+
+static void jazz_writeb(unsigned char val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_writew(unsigned short val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_writel(unsigned int val, unsigned long addr)
+{
+ map_eisa_address(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val;
+}
+
+static void jazz_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (addr & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~addr + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(addr);
+ memset((char *)waddr, val, fraglen);
+ addr += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
+
+static void jazz_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (from & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~from + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(from);
+ memcpy((void *)to, (void *)waddr, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
+
+static void jazz_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = JAZZ_EISA_BASE | (to & 0xffffff);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~to + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ map_eisa_address(to);
+ memcpy((char *)to + JAZZ_EISA_BASE, (void *)from, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+}
diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c
index 1b137cf85..805efa821 100644
--- a/arch/mips/jazz/setup.c
+++ b/arch/mips/jazz/setup.c
@@ -5,14 +5,15 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
-#include <asm/ptrace.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/jazz.h>
+#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/io.h>
@@ -35,8 +36,7 @@ extern void jazz_machine_restart(char *command);
extern void jazz_machine_halt(void);
extern void jazz_machine_power_off(void);
-static void
-jazz_irq_setup(void)
+__initfunc(static void jazz_irq_setup(void))
{
set_except_vector(0, jazz_handle_int);
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
@@ -55,8 +55,7 @@ jazz_irq_setup(void)
setup_x86_irq(2, &irq2);
}
-void
-jazz_setup(void)
+__initfunc(void jazz_setup(void))
{
irq_setup = jazz_irq_setup;
fd_cacheflush = jazz_fd_cacheflush;
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index b251d6e1a..21dd3610b 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -9,7 +9,7 @@
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
EXTRA_ASFLAGS = -mips3 -mcpu=r4000
O_TARGET := kernel.o
O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 8bb8fb41c..682e00cda 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -14,9 +14,11 @@
* and faults that can result in a task-switch. The ISA dependent TLB
* code is in arch/mips/<ISA-level>/<cputype>.S
*/
+#include <linux/config.h>
#include <linux/sys.h>
#include <asm/asm.h>
+#include <asm/current.h>
#include <asm/errno.h>
#include <asm/mipsregs.h>
#include <asm/mipsconfig.h>
@@ -53,7 +55,6 @@ reschedule:
nop
EXPORT(ret_from_sys_call)
-
lw t0,bh_mask
lw t1,bh_active # unused delay slot
and t0,t1
@@ -64,7 +65,7 @@ EXPORT(ret_from_sys_call)
beqz t1,return # -> yes
lw t1,need_resched
bnez t1,reschedule
- lw s0,current_set
+ GET_CURRENT(s0)
lw t0,task
lw a0,TASK_BLOCKED(s0)
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index a957e16bd..4c3e5bd52 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -22,6 +22,15 @@
#include <asm/bootinfo.h>
#include <asm/cpu.h>
+/*
+ * Get current task pointer
+ */
+#define GET_CURRENT(reg) \
+ lui reg, %hi(kernelsp); \
+ lw reg, %lo(kernelsp)(reg); \
+ ori reg, 8191; \
+ xori reg, 8191
+
.text
/*
* Reserved space for exception handlers.
@@ -43,8 +52,7 @@
LEAF(except_vec0_r4000)
.set mips3
mfc0 k0, CP0_BADVADDR # Get faulting address
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1) # get current task ptr
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22 # get pgd only bits
lw k1, THREAD_PGDIR(k1) # get task pg_dir
sll k0, k0, 2
@@ -71,8 +79,7 @@
LEAF(except_vec0_r4600)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -98,8 +105,7 @@
LEAF(except_vec0_r45k_bvahwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -129,8 +135,7 @@
LEAF(except_vec0_r4k_mphwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -160,8 +165,7 @@
LEAF(except_vec0_r4k_250MHZhwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -191,8 +195,7 @@
LEAF(except_vec0_r4k_MP250MHZhwbug)
.set mips3
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -224,8 +227,7 @@
LEAF(except_vec0_r2300)
.set mips1
mfc0 k0, CP0_BADVADDR
- lui k1, %hi(current_set)
- lw k1, %lo(current_set)(k1)
+ GET_CURRENT(k1) # get current task ptr
srl k0, k0, 22
lw k1, THREAD_PGDIR(k1)
sll k0, k0, 2
@@ -403,9 +405,11 @@ probe_done:
/*
* Stack for kernel and init
+ *
+ * Kernelsp will never be referenced for process 0.
*/
-9: la sp, init_user_stack+(KERNEL_STACK_SIZE-4*SZREG)
- la t0, init_kernel_stack+(KERNEL_STACK_SIZE)
+9: la sp, init_task_union+(KERNEL_STACK_SIZE-4*SZREG)
+ la t0, init_task_union+(KERNEL_STACK_SIZE)
sw t0, kernelsp
/* Disable coprocessors */
@@ -745,9 +749,13 @@ map0_sni_rm200_pci:
.org 0x6000
+ /*
+ * init_task_union follows here in the .text segment.
+ * Keep this aligned to a 8kb boundary!
+ */
+ .data
EXPORT(cache_error_buffer)
.fill 32*4,1,0
- .data
EXPORT(kernelsp)
PTR 0
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
new file mode 100644
index 000000000..cc0a19231
--- /dev/null
+++ b/arch/mips/kernel/init_task.c
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/mips/kernel/irix5sys.h b/arch/mips/kernel/irix5sys.h
index a20e619e3..be57dc1f5 100644
--- a/arch/mips/kernel/irix5sys.h
+++ b/arch/mips/kernel/irix5sys.h
@@ -105,7 +105,7 @@ SYS(irix_sgikopt, 3) /* 1083 sys_sgikopt() DC*/
SYS(sys_sysfs, 3) /* 1084 sysfs() ?V*/
SYS(irix_unimp, 0) /* 1085 XXX sys_getmsg() DC*/
SYS(irix_unimp, 0) /* 1086 XXX sys_putmsg() DC*/
-SYS(irix_poll, 3) /* 1087 sys_poll() V*/
+SYS(sys_poll, 3) /* 1087 poll() V*/
SYS(irix_sigreturn, 0) /* 1088 sigreturn() ?V*/
SYS(sys_accept, 3) /* 1089 accept() V*/
SYS(sys_bind, 3) /* 1090 bind() V*/
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 46345b308..d994155d0 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -1,4 +1,4 @@
-/* $Id: irixelf.c,v 1.8 1996/08/24 03:52:25 dm Exp $
+/*
* irixelf.c: Code to load IRIX ELF executables which conform to
* the MIPS ABI.
*
@@ -17,6 +17,7 @@
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
#include <linux/string.h>
@@ -720,16 +721,16 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
sys_close(elf_exec_fileno);
current->personality = PER_IRIX32;
- if (current->exec_domain && current->exec_domain->use_count)
- (*current->exec_domain->use_count)--;
- if (current->binfmt && current->binfmt->use_count)
- (*current->binfmt->use_count)--;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_DEC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_DEC_USE_COUNT(current->binfmt->module);
current->exec_domain = lookup_exec_domain(current->personality);
current->binfmt = &irix_format;
- if (current->exec_domain && current->exec_domain->use_count)
- (*current->exec_domain->use_count)++;
- if (current->binfmt && current->binfmt->use_count)
- (*current->binfmt->use_count)++;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_INC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_INC_USE_COUNT(current->binfmt->module);
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
@@ -1180,20 +1181,20 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
notes[0].datasz = sizeof(prstatus);
notes[0].data = &prstatus;
prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- copy_sigbits32(&prstatus.pr_sigpend, current->signal);
- copy_sigbits32(&prstatus.pr_sighold, current->blocked);
+ prstatus.pr_sigpend = current->signal;
+ prstatus.pr_sighold = current->blocked;
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+ prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
+ prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
+ prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
+ prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
+ prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
+ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
+ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
+ prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) "
"(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs));
@@ -1339,13 +1340,15 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
return has_dumped;
}
-int init_irix_binfmt(void) {
+__initfunc(int init_irix_binfmt(void))
+{
return register_binfmt(&irix_format);
}
#ifdef MODULE
-int init_module(void) {
+int init_module(void)
+{
/* Install the COFF, ELF and XOUT loaders.
* N.B. We *rely* on the table being the right size with the
* right number of free slots...
@@ -1354,7 +1357,8 @@ int init_module(void) {
}
-void cleanup_module( void) {
+void cleanup_module( void)
+{
/* Remove the IRIX ELF loaders. */
unregister_binfmt(&irix_format);
}
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index 3405904fa..e0230f9f0 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -8,6 +8,8 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <asm/uaccess.h>
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 6a5636c76..b2d7cbe49 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -8,6 +8,8 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/time.h>
#include <asm/ptrace.h>
@@ -162,7 +164,10 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
@@ -175,15 +180,19 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
current->signal |= _S(signr & 0x7f);
current->flags |= PF_SIGNALED;
+ lock_kernel(); /* 8-( */
do_exit(signr);
+ unlock_kernel();
}
}
/*
@@ -314,7 +323,7 @@ static inline void check_pending(int signum)
spin_lock(&current->sigmask_lock);
if (p->sa_handler == SIG_IGN) {
current->signal &= ~_S(signum);
- } else if if (p->sa_handler == SIG_DFL) {
+ } else if (p->sa_handler == SIG_DFL) {
if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
return;
current->signal &= ~_S(signum);
@@ -347,11 +356,9 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new,
if(sig == SIGKILL || sig == SIGSTOP) {
return -EINVAL;
}
- new_sa.sa_flags = new->flags;
- new_sa.sa_handler = (__sighandler_t) new->handler;
- new_sa.sa_mask.__sigbits[1] = new_sa.sa_mask.__sigbits[2] =
- new_sa.sa_mask.__sigbits[3] = 0;
- new_sa.sa_mask.__sigbits[0] = new->sigset[0];
+ __get_user(new_sa.sa_flags, &new->flags);
+ __get_user(new_sa.sa_handler, &(__sighandler_t) new->handler);
+ __get_user(new_sa.sa_mask, &new->sigset[0]);
if(new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
res = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
@@ -368,19 +375,22 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new,
int res = verify_area(VERIFY_WRITE, old, sizeof(*old));
if(res)
return res;
- old->flags = p->sa_flags;
- old->handler = (void *) p->sa_handler;
- old->sigset[1] = old->sigset[2] = old->sigset[3] = 0;
- old->sigset[0] = p->sa_mask.__sigbits[0];
- old->_unused0[0] = old->_unused0[1] = 0;
+ __put_user(p->sa_flags, &old->flags);
+ __put_user(p->sa_handler, &old->handler);
+ __put_user(p->sa_mask, &old->sigset[0]);
+ __put_user(0, &old->sigset[1]);
+ __put_user(0, &old->sigset[2]);
+ __put_user(0, &old->sigset[3]);
+ __put_user(0, &old->_unused0[0]);
+ __put_user(0, &old->_unused0[1]);
}
-
if(new) {
spin_lock_irq(&current->sig->siglock);
*p = new_sa;
check_pending(sig);
spin_unlock_irq(&current->sig->siglock);
}
+
return 0;
}
@@ -640,14 +650,14 @@ repeat:
__put_user(p->pid, &info->stuff.procinfo.pid);
__put_user((p->exit_code >> 8) & 0xff,
&info->stuff.procinfo.procdata.child.status);
- __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime);
- __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime);
+ __put_user(p->times.tms_utime, &info->stuff.procinfo.procdata.child.utime);
+ __put_user(p->times.tms_stime, &info->stuff.procinfo.procdata.child.stime);
p->exit_code = 0;
retval = 0;
goto end_waitsys;
case TASK_ZOMBIE:
- current->cutime += p->utime + p->cutime;
- current->cstime += p->stime + p->cstime;
+ current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
+ current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
if (ru != NULL)
getrusage(p, RUSAGE_BOTH, ru);
__put_user(SIGCHLD, &info->sig);
@@ -655,9 +665,9 @@ repeat:
__put_user(p->pid, &info->stuff.procinfo.pid);
__put_user((p->exit_code >> 8) & 0xff,
&info->stuff.procinfo.procdata.child.status);
- __put_user(p->utime,
+ __put_user(p->times.tms_utime,
&info->stuff.procinfo.procdata.child.utime);
- __put_user(p->stime,
+ __put_user(p->times.tms_stime,
&info->stuff.procinfo.procdata.child.stime);
retval = 0;
if (p->p_opptr != p->p_pptr) {
@@ -855,6 +865,8 @@ asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new,
out:
error = 0;
unlock_kernel();
+
+ return error;
}
struct irix_procset {
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index a78bc3417..0896ed1c7 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -13,6 +13,7 @@
*/
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -154,11 +155,6 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
irq_enter(cpu, irq);
kstat.interrupts[irq]++;
-#ifdef CONFIG_SGI
- prom_printf("Got irq %d, press a key.", irq);
- prom_getchar();
- romvec->imode();
-#endif
/* slow interrupts run with interrupts enabled */
sti();
action = *(irq + irq_action);
@@ -344,7 +340,7 @@ int probe_irq_off (unsigned long irqs)
return i;
}
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c
index e521ecdd9..5e71233af 100644
--- a/arch/mips/kernel/pci.c
+++ b/arch/mips/kernel/pci.c
@@ -7,6 +7,7 @@
*/
#include <linux/bios32.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/types.h>
@@ -17,7 +18,8 @@
/*
* BIOS32 replacement.
*/
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_init(unsigned long memory_start,
+ unsigned long memory_end))
{
return memory_start;
}
@@ -112,7 +114,8 @@ const char *pcibios_strerror (int error)
* specific implementation.
*/
unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end);
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_init(unsigned long memory_start,
+ unsigned long memory_end))
{
return _pcibios_init ? _pcibios_init(memory_start, memory_end)
: memory_start;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index f8b10bdea..08dd13c6c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -64,16 +64,23 @@ void release_thread(struct task_struct *dead_task)
{
}
+#define roundup(val, rnd) ({ \
+ unsigned _v = val; \
+ unsigned long _r = rnd; \
+ _v = (_v + _r - 1) & ~(_r - 1); \
+ _v; \
+})
+
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
long childksp;
- childksp = p->kernel_stack_page + KERNEL_STACK_SIZE - 8;
+ childksp = roundup((unsigned long)p, KERNEL_STACK_SIZE) - 8;
/* set up new TSS. */
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ childregs = ((struct pt_regs *) ((unsigned long)p + KERNEL_STACK_SIZE)) - 1;
*childregs = *regs;
childregs->regs[7] = 0; /* Clear error flag */
if(current->personality == PER_LINUX) {
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 41deb8f18..e61911549 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -18,18 +18,6 @@
#include <asm/page.h>
#include <asm/system.h>
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* This routine gets a long from any process space by following the page
* tables. NOTE! You should check that the long isn't on a page boundary,
@@ -47,7 +35,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -57,7 +45,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -67,7 +55,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -101,7 +89,7 @@ static void put_long(struct task_struct *tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -111,7 +99,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -121,12 +109,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -280,7 +268,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
res = -EPERM;
goto out;
}
- if (!(child = get_task(pid))) {
+ if (!(child = find_task_by_pid(pid))) {
res = -ESRCH;
goto out;
}
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 83190514b..901871a31 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -9,6 +9,7 @@
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -31,8 +32,7 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid
*/
.align 5
LEAF(r2300_resume)
- lui t5, %hi(current_set)
- lw t0, %lo(current_set)(t5)
+ GET_CURRENT(t0)
mfc0 t1,CP0_STATUS # Save status register
addu t0,a1 # Add tss offset
sw t1,THREAD_STATUS(t0)
@@ -50,7 +50,6 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid
1:
FPU_SAVE_16EVEN(t0, t1)
2:
- sw a0,%lo(current_set)(t5) # Switch current task
addu a0,a1 # Add tss offset
lw t0,THREAD_PGDIR(a0) # Switch the root pointer
li t1,TLB_ROOT # get PFN
diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S
index 432c65215..5c9ad4d84 100644
--- a/arch/mips/kernel/r4k_misc.S
+++ b/arch/mips/kernel/r4k_misc.S
@@ -10,6 +10,7 @@
#include <asm/offset.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -29,9 +30,8 @@
*/
#define LOAD_PTE(pte, ptr) \
mfc0 pte, CP0_BADVADDR; \
- lui ptr, %hi(current_set); \
srl pte, pte, 22; \
- lw ptr, %lo(current_set)(ptr); \
+ GET_CURRENT(ptr); \
sll pte, pte, 2; \
lw ptr, THREAD_PGDIR(ptr); \
addu ptr, pte, ptr; \
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 78ced5659..97e253028 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -1,4 +1,4 @@
-/* $Id: r4k_switch.S,v 1.8 1996/07/10 01:24:20 dm Exp $
+/*
* r4k_switch.S: R4xx0 specific task switching code.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
@@ -9,6 +9,7 @@
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/current.h>
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
@@ -24,8 +25,7 @@
.set mips3
.align 5
LEAF(r4xx0_resume)
- lui t5, %hi(current_set)
- lw t0, %lo(current_set)(t5)
+ GET_CURRENT(t0)
mfc0 t1, CP0_STATUS
nop
sw t1, THREAD_STATUS(t0)
@@ -43,7 +43,6 @@
1:
FPU_SAVE_16EVEN(t0, t1) # clobbers t1
2:
- sw a0, %lo(current_set)(t5)
lw a3, TASK_MM(a0)
lw a2, THREAD_STATUS(a0)
lw a3, MM_CONTEXT(a3)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 2e2b074f9..7616fa7c6 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -123,17 +124,17 @@ void (*irq_setup)(void);
*/
unsigned long isa_slot_offset;
-static void default_irq_setup(void)
+__initfunc(static void default_irq_setup(void))
{
panic("Unknown machtype in init_IRQ");
}
-static void default_fd_cacheflush(const void *addr, size_t size)
+__initfunc(static void default_fd_cacheflush(const void *addr, size_t size))
{
}
-void setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
{
unsigned long memory_end;
tag* atag;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 848f0742b..304dc6418 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -307,7 +307,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
@@ -318,11 +321,15 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
schedule();
continue;
- case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ case SIGBUS:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
spin_lock_irq(&current->sigmask_lock);
diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
index 4cf778acb..6c7d3988c 100644
--- a/arch/mips/kernel/syscalls.h
+++ b/arch/mips/kernel/syscalls.h
@@ -174,6 +174,7 @@ SYS(sys_mlock, 2)
SYS(sys_munlock, 2) /* 4155 */
SYS(sys_mlockall, 1)
SYS(sys_munlockall, 0)
+SYS(sys_nfsservctl, 3)
SYS(sys_sched_setparam,2)
SYS(sys_sched_getparam,2)
SYS(sys_sched_setscheduler,3) /* 4160 */
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 9a4ddca3f..7917664fd 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -17,6 +17,8 @@
#include <linux/elf.h>
#include <linux/msg.h>
#include <linux/shm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/utsname.h>
#include <asm/ptrace.h>
@@ -24,26 +26,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-/* 2,000 lines of complete and utter shit coming up... */
-
-/* Utility routines. */
-static inline struct task_struct *find_process_by_pid(pid_t pid)
-{
- struct task_struct *p, *q;
-
- if (pid == 0)
- p = current;
- else {
- p = 0;
- for_each_task(q) {
- if (q && q->pid == pid) {
- p = q;
- break;
- }
- }
- }
- return p;
-}
+/* 2,300 lines of complete and utter shit coming up... */
/* The sysmp commands supported thus far. */
#define MP_PGSIZE 14 /* Return system page size in v1. */
@@ -70,7 +53,6 @@ asmlinkage int irix_sysmp(struct pt_regs *regs)
break;
}
-out:
unlock_kernel();
return error;
}
@@ -114,7 +96,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs)
printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n",
current->comm, current->pid);
- task = find_process_by_pid(regs->regs[base + 5]);
+ task = find_task_by_pid(regs->regs[base + 5]);
if(!task) {
error = -ESRCH;
break;
@@ -233,7 +215,6 @@ asmlinkage int irix_prctl(struct pt_regs *regs)
break;
}
-out:
unlock_kernel();
return error;
}
@@ -658,7 +639,6 @@ asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags,
dev_name, dir_name, flags, type, data, datalen);
ret = sys_mount(dev_name, dir_name, type, flags, data);
-out:
unlock_kernel();
return ret;
}
@@ -781,22 +761,23 @@ asmlinkage int irix_setpgrp(int flags)
printk("returning %d\n", current->pgrp);
#endif
-out:
unlock_kernel();
return error;
}
asmlinkage int irix_times(struct tms * tbuf)
{
+ int error;
+
lock_kernel();
if (tbuf) {
- int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
+ error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
if (error)
goto out;
- __put_user(current->utime,&tbuf->tms_utime);
- __put_user(current->stime,&tbuf->tms_stime);
- __put_user(current->cutime,&tbuf->tms_cutime);
- __put_user(current->cstime,&tbuf->tms_cstime);
+ __put_user(current->times.tms_utime,&tbuf->tms_utime);
+ __put_user(current->times.tms_stime,&tbuf->tms_stime);
+ __put_user(current->times.tms_cutime,&tbuf->tms_cutime);
+ __put_user(current->times.tms_cstime,&tbuf->tms_cstime);
}
error = 0;
@@ -845,169 +826,6 @@ out:
return error;
}
-/* sys_poll() support... */
-#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
-#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
-#define POLLWRBAND 256
-
-#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN)
-#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT)
-#define LINUX_POLLERR (POLLERR)
-
-static inline void free_wait(select_table * p)
-{
- struct select_table_entry * entry = p->entry + p->nr;
-
- while (p->nr > 0) {
- p->nr--;
- entry--;
- remove_wait_queue(entry->wait_address,&entry->wait);
- }
-}
-
-
-/* Copied directly from fs/select.c */
-static int check(int flag, select_table * wait, struct file * file)
-{
- struct inode * inode;
- struct file_operations *fops;
- int (*select) (struct inode *, struct file *, int, select_table *);
-
- inode = file->f_inode;
- if ((fops = file->f_op) && (select = fops->select))
- return select(inode, file, flag, wait)
- || (wait && select(inode, file, flag, NULL));
- if (S_ISREG(inode->i_mode))
- return 1;
- return 0;
-}
-
-struct poll {
- int fd;
- short events;
- short revents;
-};
-
-int irix_poll(struct poll * ufds, size_t nfds, int timeout)
-{
- int i,j, count, fdcount, error, retflag;
- struct poll * fdpnt;
- struct poll * fds, *fds1;
- select_table wait_table, *wait;
- struct select_table_entry *entry;
-
- lock_kernel();
- if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll))))
- goto out;
-
- if (nfds > NR_OPEN) {
- error = -EINVAL;
- goto out;
- }
-
- if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL))
- || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) {
- error = -ENOMEM;
- goto out;
- }
-
- copy_from_user(fds, ufds, nfds*sizeof(struct poll));
-
- if (timeout < 0)
- current->timeout = 0x7fffffff;
- else {
- current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ));
- if (current->timeout <= jiffies)
- current->timeout = 0;
- }
-
- count = 0;
- wait_table.nr = 0;
- wait_table.entry = entry;
- wait = &wait_table;
-
- for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
- i = fdpnt->fd;
- fdpnt->revents = 0;
- if (!current->files->fd[i] || !current->files->fd[i]->f_inode)
- fdpnt->revents = POLLNVAL;
- }
-repeat:
- current->state = TASK_INTERRUPTIBLE;
- for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
- i = fdpnt->fd;
-
- if(i < 0) continue;
- if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue;
-
- if ((fdpnt->events & LINUX_POLLIN)
- && check(SEL_IN, wait, current->files->fd[i])) {
- retflag = 0;
- if (fdpnt->events & POLLIN)
- retflag = POLLIN;
- if (fdpnt->events & POLLRDNORM)
- retflag = POLLRDNORM;
- fdpnt->revents |= retflag;
- count++;
- wait = NULL;
- }
-
- if ((fdpnt->events & LINUX_POLLOUT) &&
- check(SEL_OUT, wait, current->files->fd[i])) {
- fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events);
- count++;
- wait = NULL;
- }
-
- if (check(SEL_EX, wait, current->files->fd[i])) {
- fdpnt->revents |= POLLHUP;
- count++;
- wait = NULL;
- }
- }
-
- if ((current->signal & (~current->blocked))) {
- error = -EINTR;
- goto out;
- }
-
- wait = NULL;
- if (!count && current->timeout > jiffies) {
- schedule();
- goto repeat;
- }
-
- free_wait(&wait_table);
- free_page((unsigned long) entry);
-
- /* OK, now copy the revents fields back to user space. */
- fds1 = fds;
- fdcount = 0;
- for(i=0; i < (int)nfds; i++, ufds++, fds++) {
- if (fds->revents) {
- fdcount++;
- }
- put_user(fds->revents, &ufds->revents);
- }
- kfree(fds1);
- current->timeout = 0;
- current->state = TASK_RUNNING;
- error = fdcount;
-
-out:
- unlock_kernel();
- return error;
-}
-
asmlinkage unsigned long irix_gethostid(void)
{
lock_kernel();
@@ -1263,7 +1081,6 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp)
printk("error = %d\n", error);
#endif
-out:
unlock_kernel();
return error;
}
@@ -1443,11 +1260,11 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
if(error)
goto out;
error = irix_xstat32_xlate(&kb, statbuf);
- goto error;
+ goto out;
}
case 3: {
- sys_newlstat(filename, statbuf);
+ error = sys_newlstat(filename, statbuf);
#ifdef DEBUG_XSTAT
printk("error[%d]\n", error);
#endif
@@ -1456,7 +1273,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
irix_xstat64_xlate(statbuf);
error = 0;
- goto error;
+ goto out;
}
default:
@@ -1466,7 +1283,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
out:
unlock_kernel();
- return errno;
+ return error;
}
extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
@@ -2018,13 +1835,13 @@ out:
asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf)
{
- int errno;
+ int error;
lock_kernel();
printk("[%s:%d] irix_getmountid(%s, %p)\n",
current->comm, current->pid, fname, midbuf);
- errno = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4));
- if(errno)
+ error = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4));
+ if(error)
goto out;
/*
@@ -2142,7 +1959,7 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count
buf.error = 0;
error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32);
if (error < 0)
- goto out
+ goto out;
lastdirent = buf.previous;
if (!lastdirent) {
error = buf.error;
@@ -2431,6 +2248,8 @@ asmlinkage int irix_fcntl(int fd, int cmd, int arg)
asmlinkage int irix_ulimit(int cmd, int arg)
{
+ int retval;
+
lock_kernel();
switch(cmd) {
case 1:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index aa4547456..fd57f6d0e 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -7,6 +7,7 @@
* found in some MIPS systems.
*/
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
@@ -299,7 +300,7 @@ static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
void (*board_time_init)(struct irqaction *irq);
-void time_init(void)
+__initfunc(void time_init(void))
{
unsigned int year, mon, day, hour, min, sec;
int i;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 17b1f9a28..cdbcacb43 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -17,6 +17,7 @@
* Modified for R3000 by Paul M. Antoine, 1995, 1996
*/
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -110,10 +111,8 @@ void show_registers(char * str, struct pt_regs * regs, long err)
/*
* Dump the stack
*/
- if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, current->kernel_stack_page);
+ current->comm, current->pid, (unsigned long)current);
for(i=0;i<5;i++)
printk("%08x ", *sp++);
stack = (int *) sp;
@@ -389,7 +388,7 @@ void do_reserved(struct pt_regs *regs)
unlock_kernel();
}
-static void watch_init(unsigned long cputype)
+static inline void watch_init(unsigned long cputype)
{
switch(cputype) {
case CPU_R10000:
@@ -427,7 +426,7 @@ extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
extern asmlinkage void r4xx0_resume(void *tsk);
extern asmlinkage void r2300_resume(void *tsk);
-void trap_init(void)
+__initfunc(void trap_init(void))
{
extern char except_vec0_r4000, except_vec0_r4600, except_vec0_r2300;
extern char except_vec1_generic, except_vec2_generic;
diff --git a/arch/mips/mips/Makefile b/arch/mips/mips/Makefile
new file mode 100644
index 000000000..b252e2fe4
--- /dev/null
+++ b/arch/mips/mips/Makefile
@@ -0,0 +1,39 @@
+#
+# PROM Entries for the big endian firmware used in the Mips Computer
+# System, Inc. machines. Beware: some of the machines seem to be
+# different.
+#
+# Copyright (C) 1997 Ralf Baechle
+#
+prom-entries= reset exec restart reinit reboot autoboot open read write ioctl \
+ close getchar putchar showchar gets puts printf initproto protoenable \
+ protodisable getpkt putpkt orw_rmw orh_rmw orb_rmw andw_rmw andh_rmw \
+ andb_rmw flushcache clearcache setjmp longjmp bevutlb getenv setenv \
+ atob strcmp strlen strcpy strcat parser range argvize help dumpcmd \
+ setenvcmd unsetenvcmd printenvcmd bevexcept enablecmd disablecmd \
+ clearnofault notimplement nv_get nv_set
+asm-files=$(addsuffix .S,$(prom-entries))
+object-files=$(addsuffix .o,$(prom-entries))
+
+CC=mipsel-linux-gcc
+AR=mipsel-linux-ar
+CFLAGS=-O2 -mno-abicalls -fno-pic -G0 -Wall
+
+all: libprom.a
+
+libprom.a: $(asm-files)
+ set -e;for i in $(prom-entries); do \
+ $(CC) $(CFLAGS) -c -o $$i.o $$i.S; \
+ $(AR) rcv libprom.a $$i.o; \
+ done
+
+$(asm-files): mkprom
+ set -e;for i in $(prom-entries); do \
+ mkprom $$i; \
+ done
+
+clean:
+ rm -f $(object-files)
+
+distclean:
+ rm -rf $(asm-files) libprom.a
diff --git a/arch/mips/mips/mkprom b/arch/mips/mips/mkprom
new file mode 100755
index 000000000..9e4cdf465
--- /dev/null
+++ b/arch/mips/mips/mkprom
@@ -0,0 +1,25 @@
+#
+# Generate PROM library stubs for the firmware used in the
+# Mips Computer System, Inc. machines. Beware: some of the
+# machines seem to be different.
+#
+# Copyright (C) 1997 Ralf Baechle
+#
+fname=$1
+ucase=`echo $fname | tr 'a-z' 'A-Z'`
+cat << EOF | sed -e "s/@1@/$fname/" -e "s/@2@/$ucase/" >$fname.S
+/*
+ * WARNING: This file has been generated automatically. Do not edit!
+ *
+ * Stub for the Mips firmware @1@() function.
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsprom.h>
+
+LEAF(mips_prom_@1@)
+ lw t0,__mips_prom_entry_offset
+ addu t0,PROM_@2@
+ jr t0
+ END(mips_prom_@1@)
+EOF
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index d12159903..1205b2bf3 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -9,6 +9,6 @@
O_TARGET := mm.o
O_OBJS := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \
- andes.o loadmmu.o stack.o
+ andes.o loadmmu.o
include $(TOPDIR)/Rules.make
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 4fdd98155..3ad703b1f 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -70,7 +70,7 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, writeaccess);
+ handle_mm_fault(tsk, vma, address, writeaccess);
up(&mm->mmap_sem);
goto out;
diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c
index 5f1bcbfa6..f83f41df8 100644
--- a/arch/mips/mm/r4xx0.c
+++ b/arch/mips/mm/r4xx0.c
@@ -1,4 +1,4 @@
-/* $Id: r4xx0.c,v 1.19 1996/08/02 11:11:36 dm Exp $
+/*
* r4xx0.c: R4000 processor variant specific MMU/Cache routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -325,28 +325,6 @@ static inline void r4k_flush_cache_all_d32i32(void)
restore_flags(flags);
}
-static inline struct vm_area_struct *
-find_mm_vma(struct mm_struct *mm, unsigned long addr)
-{
- struct vm_area_struct * result = NULL;
-
- if (mm) {
- struct vm_area_struct * tree = mm->mmap_avl;
- for (;;) {
- if (tree == avl_empty)
- break;
- if (tree->vm_end > addr) {
- result = tree;
- if (tree->vm_start <= addr)
- break;
- tree = tree->vm_avl_left;
- } else
- tree = tree->vm_avl_right;
- }
- }
- return result;
-}
-
static void
r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
unsigned long start,
@@ -362,7 +340,7 @@ r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s16d16i16();
@@ -407,7 +385,7 @@ r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s32d16i16();
@@ -451,7 +429,7 @@ static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s64d16i16();
@@ -495,7 +473,7 @@ static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s128d16i16();
@@ -539,7 +517,7 @@ static void r4k_flush_cache_range_s16d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s16d32i32();
@@ -583,7 +561,7 @@ static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s32d32i32();
@@ -627,7 +605,7 @@ static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s64d32i32();
@@ -671,7 +649,7 @@ static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
#ifdef DEBUG_CACHE
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
- vma = find_mm_vma(mm, start);
+ vma = find_vma(mm, start);
if(vma) {
if(mm->context != current->mm->context) {
r4k_flush_cache_all_s128d32i32();
diff --git a/arch/mips/mm/stack.c b/arch/mips/mm/stack.c
deleted file mode 100644
index 89fb6dc64..000000000
--- a/arch/mips/mm/stack.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Kernel stack allocation/deallocation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997 by Ralf Baechle
- *
- * (This is _bad_ if the free page pool is fragmented ...)
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/processor.h>
-
-extern unsigned long alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long stack;
- stack = __get_free_pages(GFP_KERNEL, 1, 0);
-
- return stack;
-}
-
-extern void free_kernel_stack(unsigned long stack)
-{
- free_pages(stack, 1);
-}
diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c
index 19b744fdb..fe60c03c8 100644
--- a/arch/mips/sgi/kernel/indy_int.c
+++ b/arch/mips/sgi/kernel/indy_int.c
@@ -16,6 +16,8 @@
#include <linux/timex.h>
#include <linux/malloc.h>
#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
@@ -51,6 +53,7 @@ extern asmlinkage void indyIRQ(void);
extern void rs_kgdb_hook(int);
#endif
+unsigned int local_irq_count[NR_CPUS];
unsigned long spurious_count = 0;
/* Local IRQ's are layed out logically like this:
@@ -255,6 +258,15 @@ int get_irq_list(char *buf)
return len;
}
+atomic_t __mips_bh_counter;
+
+#ifdef __SMP__
+#error Send superfluous SMP boxes to ralf@uni-koblenz.de
+#else
+#define irq_enter(cpu, irq) (++local_irq_count[cpu])
+#define irq_exit(cpu, irq) (--local_irq_count[cpu])
+#endif
+
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
@@ -264,8 +276,9 @@ int get_irq_list(char *buf)
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- lock_kernel();
struct irqaction * action = *(irq + irq_action);
+
+ lock_kernel();
kstat.interrupts[irq]++;
printk("Got irq %d, press a key.", irq);
prom_getchar();
diff --git a/arch/mips/sgi/kernel/setup.c b/arch/mips/sgi/kernel/setup.c
index 58b7695b3..e0482e116 100644
--- a/arch/mips/sgi/kernel/setup.c
+++ b/arch/mips/sgi/kernel/setup.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <asm/reboot.h>
#include <asm/vector.h>
#include <asm/sgialib.h>
#include <asm/sgi.h>
diff --git a/arch/mips/sgi/prom/misc.c b/arch/mips/sgi/prom/misc.c
index 47051a1b3..53ee61cfe 100644
--- a/arch/mips/sgi/prom/misc.c
+++ b/arch/mips/sgi/prom/misc.c
@@ -1,9 +1,9 @@
-/* $Id: misc.c,v 1.3 1996/08/07 02:54:12 dm Exp $
+/*
* misc.c: Miscellaneous ARCS PROM routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
-
+#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/sgialib.h>
@@ -51,7 +51,9 @@ void prom_halt(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->halt();
}
@@ -60,7 +62,9 @@ void prom_powerdown(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->pdown();
}
@@ -70,7 +74,9 @@ void prom_restart(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->restart();
}
@@ -79,7 +85,9 @@ void prom_reboot(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->reboot();
}
@@ -88,7 +96,9 @@ void prom_imode(void)
{
shutoff_r4600_cache();
initialize_kbd();
+#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+#endif
cli();
romvec->imode();
}
diff --git a/arch/mips/sni/.cvsignore b/arch/mips/sni/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/arch/mips/sni/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index f0bc3e600..9bd570ff0 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -13,7 +13,7 @@
all: sni.o
O_TARGET := sni.o
-O_OBJS := hw-access.o int-handler.o pci.o reset.o setup.o
+O_OBJS := hw-access.o int-handler.o io.o pci.o reset.o setup.o
int-handler.o: int-handler.S
diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S
index f60c82251..d051c8b13 100644
--- a/arch/mips/sni/int-handler.S
+++ b/arch/mips/sni/int-handler.S
@@ -1,7 +1,7 @@
/*
* SNI RM200 PCI specific interrupt handler code.
*
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994 - 1997 by Ralf Baechle
*/
#include <asm/asm.h>
#include <linux/config.h>
@@ -150,30 +150,17 @@ poll_second: li a0,0x0f
#endif /* CONFIG_PCNET32 */
-/*
- * FIXME: This is definatly wrong but I'll have to do it this way
- * 'till I get more hardware info.
- * XXX: Apparently the NCR is attached to interrupt #2.
- */
#ifdef CONFIG_SCSI_NCR53C8XX
/*
- * FIXME: detect this address
- */
-#define NCR_BASE 0xb8000000
-
-/* Offsets from base I/O address. */
-#define NCR_INTF 0x14
-
-/*
* ... check if we were interrupted by the NCR ...
*/
-3: lb t0,NCR_BASE+NCR_INTF
- andi t0,7
- beqz t0,3f # no NCR interrupt?
+3: lb t0,PCIMT_CSITPEND
+ andi t0,0x40
+ bnez t0,3f # bit 6 == 0 -> SCSI IRQ
nop # delay slot
jal do_fast_IRQ
- li a0,5 # delay slot
+ li a0,PCIMT_IRQ_SCSI # delay slot
j return
nop # delay slot
diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c
new file mode 100644
index 000000000..f62fdc2d7
--- /dev/null
+++ b/arch/mips/sni/io.c
@@ -0,0 +1,172 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Low level I/O functions for SNI.
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+#include <asm/sni.h>
+
+unsigned char sni_map_isa_cache;
+
+#define unused __attribute__((unused))
+
+/*
+ * The PCIMT_CSMAPISA is shared by all processors; we need locking.
+ *
+ * XXX It's legal to use all the I/O memory access functions in interrupt
+ * code, so we need to use the _irq locking stuff which may result in
+ * significant IRQ latencies.
+ */
+static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Urgs... We only can see a 16mb window of the 4gb EISA address space
+ * at PCIMT_EISA_BASE. Maladia segmentitis ...
+ *
+ * XXX Check out if accessing PCIMT_CSMAPISA really is slow.
+ * For now assume so.
+ */
+static inline void update_isa_cache(unsigned long address)
+{
+ unsigned char upper;
+
+ upper = address >> 24;
+ if (sni_map_isa_cache != upper) {
+ sni_map_isa_cache = upper;
+ *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper;
+ }
+}
+
+static unsigned char sni_readb(unsigned long addr)
+{
+ unsigned char res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned short sni_readw(unsigned long addr)
+{
+ unsigned short res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned int sni_readl(unsigned long addr)
+{
+ unsigned int res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static void sni_writeb(unsigned char val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writew(unsigned short val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writel(unsigned int val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (addr & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~addr + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(addr);
+ memset((char *)waddr, val, fraglen);
+ addr += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (from & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~from + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(from);
+ memcpy((void *)to, (void *)waddr, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (to & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~to + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(to);
+ memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
index 06edb268f..917d07a81 100644
--- a/arch/mips/sni/pci.c
+++ b/arch/mips/sni/pci.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
#include <linux/bios32.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -18,18 +19,26 @@
extern inline u32 mkaddr(unsigned char bus, unsigned char dev_fn,
unsigned char where)
{
- return (((bus & 0xff) << 0x10) |
- ((dev_fn & 0xff) << 0x08) |
- ((where & 0xfc)));
+ return ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) |
+ (where & 0xfc);
}
static unsigned long sni_rm200_pcibios_fixup (unsigned long memory_start,
unsigned long memory_end)
{
- /* I guess it's ok to do exactly nothing. */
+ /*
+ * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards.
+ * Take care of RM300 revision D boards for where the network
+ * slot became an ordinary PCI slot.
+ */
return memory_start;
}
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
unsigned char dev_fn,
unsigned char where,
@@ -39,7 +48,7 @@ static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -56,7 +65,7 @@ static int sni_rm200_pcibios_read_config_word (unsigned char bus,
return PCIBIOS_BAD_REGISTER_NUMBER;
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -110,7 +119,7 @@ static int sni_rm200_pcibios_write_config_dword (unsigned char bus,
return PCIBIOS_SUCCESSFUL;
}
-unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end))
{
_pcibios_fixup = sni_rm200_pcibios_fixup;
_pcibios_read_config_byte = sni_rm200_pcibios_read_config_byte;
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 1a7a1387d..7fa76a490 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -5,11 +5,12 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
#include <asm/ptrace.h>
#include <linux/ioport.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/pci.h>
@@ -40,8 +41,7 @@ extern void sni_machine_restart(char *command);
extern void sni_machine_halt(void);
extern void sni_machine_power_off(void);
-static void
-sni_irq_setup(void)
+__initfunc(static void sni_irq_setup(void))
{
set_except_vector(0, sni_rm200_pci_handle_int);
request_region(0x20,0x20, "pic1");
@@ -57,7 +57,7 @@ sni_irq_setup(void)
void (*board_time_init)(struct irqaction *irq);
-static void sni_rm200_pci_time_init(struct irqaction *irq)
+__initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq))
{
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -67,8 +67,9 @@ static void sni_rm200_pci_time_init(struct irqaction *irq)
}
unsigned char aux_device_present;
-unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
- unsigned long memory_end);
+extern unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
+ unsigned long memory_end);
+extern unsigned char sni_map_isa_cache;
/*
* A bit more gossip about the iron we're running on ...
@@ -92,8 +93,7 @@ static inline void sni_pcimt_detect(void)
printk("%s.\n", boardtype);
}
-void
-sni_rm200_pci_setup(void)
+__initfunc(void sni_rm200_pci_setup(void))
{
tag *atag;
@@ -127,7 +127,14 @@ sni_rm200_pci_setup(void)
fd_cacheflush = sni_fd_cacheflush; // Will go away
feature = &sni_rm200_pci_feature;
port_base = SNI_PORT_BASE;
+
+ /*
+ * Setup (E)ISA I/O memory access stuff
+ */
isa_slot_offset = 0xb0000000;
+ // sni_map_isa_cache = 0;
+ EISA_bus = 1;
+
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
/* XXX FIXME: CONFIG_RTC */
@@ -140,8 +147,6 @@ sni_rm200_pci_setup(void)
_machine_halt = sni_machine_halt;
_machine_power_off = sni_machine_power_off;
- if (mips_machtype == MACH_SNI_RM200_PCI)
- EISA_bus = 1;
aux_device_present = 0xaa;
/*
diff --git a/arch/mips/tools/.cvsignore b/arch/mips/tools/.cvsignore
new file mode 100644
index 000000000..2a1642034
--- /dev/null
+++ b/arch/mips/tools/.cvsignore
@@ -0,0 +1 @@
+.depend offset.s offset.h
diff --git a/arch/mips/tools/offset.c b/arch/mips/tools/offset.c
index 3bb46de6e..a8660dcf6 100644
--- a/arch/mips/tools/offset.c
+++ b/arch/mips/tools/offset.c
@@ -77,12 +77,11 @@ void output_task_defines(void)
{
text("/* MIPS task_struct offsets. */");
offset("#define TASK_STATE ", struct task_struct, state);
+ offset("#define TASK_COUNTER ", struct task_struct, counter);
offset("#define TASK_PRIORITY ", struct task_struct, priority);
offset("#define TASK_SIGNAL ", struct task_struct, signal);
offset("#define TASK_BLOCKED ", struct task_struct, blocked);
offset("#define TASK_FLAGS ", struct task_struct, flags);
- offset("#define TASK_SAVED_KSTACK ", struct task_struct, saved_kernel_stack);
- offset("#define TASK_KSTACK_PG ", struct task_struct, kernel_stack_page);
offset("#define TASK_MM ", struct task_struct, mm);
linefeed;
}
diff --git a/arch/mips/tools/offset.h b/arch/mips/tools/offset.h
deleted file mode 100644
index c5e6f37fa..000000000
--- a/arch/mips/tools/offset.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */
-
-#ifndef _MIPS_OFFSET_H
-#define _MIPS_OFFSET_H
-
-/* MIPS pt_regs offsets. */
-#define PT_R0 24
-#define PT_R1 28
-#define PT_R2 32
-#define PT_R3 36
-#define PT_R4 40
-#define PT_R5 44
-#define PT_R6 48
-#define PT_R7 52
-#define PT_R8 56
-#define PT_R9 60
-#define PT_R10 64
-#define PT_R11 68
-#define PT_R12 72
-#define PT_R13 76
-#define PT_R14 80
-#define PT_R15 84
-#define PT_R16 88
-#define PT_R17 92
-#define PT_R18 96
-#define PT_R19 100
-#define PT_R20 104
-#define PT_R21 108
-#define PT_R22 112
-#define PT_R23 116
-#define PT_R24 120
-#define PT_R25 124
-#define PT_R26 128
-#define PT_R27 132
-#define PT_R28 136
-#define PT_R29 140
-#define PT_R30 144
-#define PT_R31 148
-#define PT_LO 152
-#define PT_HI 156
-#define PT_OR2 160
-#define PT_OR7 164
-#define PT_EPC 168
-#define PT_BVADDR 172
-#define PT_STATUS 176
-#define PT_CAUSE 180
-#define PT_SIZE 184
-
-/* MIPS task_struct offsets. */
-#define TASK_STATE 0
-#define TASK_PRIORITY 8
-#define TASK_SIGNAL 12
-#define TASK_BLOCKED 16
-#define TASK_FLAGS 20
-#define TASK_SAVED_KSTACK 84
-#define TASK_KSTACK_PG 88
-#define TASK_MM 912
-
-/* MIPS specific thread_struct offsets. */
-#define THREAD_REG16 544
-#define THREAD_REG17 548
-#define THREAD_REG18 552
-#define THREAD_REG19 556
-#define THREAD_REG20 560
-#define THREAD_REG21 564
-#define THREAD_REG22 568
-#define THREAD_REG23 572
-#define THREAD_REG28 576
-#define THREAD_REG29 580
-#define THREAD_REG30 584
-#define THREAD_REG31 588
-#define THREAD_STATUS 592
-#define THREAD_FPU 600
-#define THREAD_BVADDR 864
-#define THREAD_ECODE 868
-#define THREAD_TRAPNO 872
-#define THREAD_KSP 876
-#define THREAD_PGDIR 880
-#define THREAD_MFLAGS 884
-#define THREAD_CURDS 888
-#define THREAD_TRAMP 892
-#define THREAD_OLDCTX 896
-
-/* Linux mm_struct offsets. */
-#define MM_COUNT 0
-#define MM_PGD 4
-#define MM_CONTEXT 8
-
-#endif /* !(_MIPS_OFFSET_H) */
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index e137e1171..c2a2989ec 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -855,5 +855,6 @@ sys_call_table:
.long sys_mremap
.long SYMBOL_NAME(sys_setresuid)
.long SYMBOL_NAME(sys_getresuid)
- .space (NR_syscalls-165)*4
+ .long SYMBOL_NAME(sys_nfsservctl)
+ .space (NR_syscalls-166)*4
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 8dc0e61ca..ee21c5cbe 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -29,6 +29,24 @@
#include <asm/io.h>
#include <asm/ppc_machine.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+
+struct mm_struct init_mm = INIT_MM;
+struct task_struct init_task = INIT_TASK;
+
+
int dump_fpu(void);
void hard_reset_now(void);
void switch_to(struct task_struct *, struct task_struct *);
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 2d960c8cd..dc8a95302 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -42,18 +42,6 @@
static int regoff[] = {
};
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* Get contents of register REGNO in task TASK.
*/
@@ -394,7 +382,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = get_task(pid)))
+ if (!(child = find_task_by_pid(pid)))
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 6a6ffdb89..ee2381dba 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -58,69 +58,62 @@ pte_t __bad_page(void)
void show_mem(void)
{
- unsigned long i,free = 0,total = 0,reserved = 0;
- unsigned long shared = 0;
- PTE *ptr;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
-
- printk("Mem-info:\n");
- show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = MAP_NR(high_memory);
- while (i-- > 0) {
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (!atomic_read(&mem_map[i].count))
- free++;
- else
- shared += atomic_read(&mem_map[i].count) - 1;
- }
- printk("%lu pages of RAM\n",total);
- printk("%lu free pages\n",free);
- printk("%lu reserved pages\n",reserved);
- printk("%lu pages shared\n",shared);
- show_buffers();
+ struct task_struct *p;
+ unsigned long i,free = 0,total = 0,reserved = 0;
+ unsigned long shared = 0;
+ PTE *ptr;
+ unsigned long full = 0, overflow = 0;
+ unsigned int ti;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = MAP_NR(high_memory);
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (!atomic_read(&mem_map[i].count))
+ free++;
+ else
+ shared += atomic_read(&mem_map[i].count) - 1;
+ }
+ printk("%lu pages of RAM\n",total);
+ printk("%lu free pages\n",free);
+ printk("%lu reserved pages\n",reserved);
+ printk("%lu pages shared\n",shared);
+ show_buffers();
#ifdef CONFIG_NET
- show_net_buffers();
+ show_net_buffers();
#endif
#ifdef HASHSTATS
- printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
- for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ )
- {
- if ( hashhits[i] >= 20 )
- {
- printk("[%lu] \t %lu\n", i,hashhits[i]);
- }
- }
+ printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
+ for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
+ if ( hashhits[i] >= 20 )
+ printk("[%lu] \t %lu\n", i,hashhits[i]);
+ }
#endif
- for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++)
- {
- if (ptr->v)
- {
- full++;
- if (ptr->h == 1)
- overflow++;
- }
- }
- printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
- Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
- full,Hash_size/sizeof(PTE),
- (full*100)/(Hash_size/sizeof(PTE)),
- overflow);
- printk(" Task context vsid0\n");
- for ( ti = 0; ti < NR_TASKS ; ti++ );
- {
- if ( task[ti] )
- {
- printk("%5d %8x %8x\n",
- task[ti]->pid,task[ti]->mm->context,
- ((SEGREG *)task[ti]->tss.segs)[0].vsid);
- }
- }
-
+ for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
+ if (ptr->v) {
+ full++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+ printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
+ Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
+ full,Hash_size/sizeof(PTE),
+ (full*100)/(Hash_size/sizeof(PTE)),
+ overflow);
+ printk(" Task context vsid0\n");
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ printk("%5d %8x %8x\n",
+ p->pid,p->mm->context,
+ ((SEGREG *)p->tss.segs)[0].vsid);
+ }
+ read_unlock(&tasklist_lock);
}
extern unsigned long free_area_init(unsigned long, unsigned long);
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 587cfc616..92c73de32 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $
+# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -21,7 +21,7 @@ CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7
#LINKFLAGS = -N -Ttext 0xf0004000
LINKFLAGS = -T arch/sparc/vmlinux.lds
-HEAD := arch/sparc/kernel/head.o
+HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
arch/sparc/prom
diff --git a/arch/sparc/ap1000/bnet.c b/arch/sparc/ap1000/bnet.c
index 9305b0a55..974501d79 100644
--- a/arch/sparc/ap1000/bnet.c
+++ b/arch/sparc/ap1000/bnet.c
@@ -872,12 +872,12 @@ static void reply_kill(struct cap_request *req)
len = req->size - sizeof(*req);
if (len == 0) {
int pid = req->data[1];
- for_each_task(p)
- if (p->pid == pid) {
- send_sig(sig,p,1);
- return;
- }
- printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
+ p = find_task_by_pid(pid);
+
+ if(p)
+ send_sig(sig, p, 1);
+ else
+ printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
return;
}
@@ -889,9 +889,11 @@ static void reply_kill(struct cap_request *req)
read_bif(name,len);
name[len] = 0;
+ read_lock(&tasklist_lock);
for_each_task(p)
if (strcmp(name,p->comm) == 0)
send_sig(sig,p,1);
+ read_unlock(&tasklist_lock);
}
diff --git a/arch/sparc/ap1000/hw.c b/arch/sparc/ap1000/hw.c
index c36150c4e..aabe15a3b 100644
--- a/arch/sparc/ap1000/hw.c
+++ b/arch/sparc/ap1000/hw.c
@@ -86,14 +86,21 @@ static void show_task(struct task_struct *t)
static void show_ptasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
- for (i=MPP_TASK_BASE;i<NR_TASKS;i++)
- if (task[i]) {
- show_task(task[i]);
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ struct task_struct **tp = p->tarray_ptr;
+
+ if(tp >= &task[MPP_TASK_BASE]) {
+ show_task(p);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
+
if (count == 0)
printk("no parallel tasks on cell %d\n",mpp_cid());
}
@@ -101,14 +108,18 @@ static void show_ptasks(void)
static void show_utasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->uid > 1) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if(p->uid > 1) {
show_task(task[i]);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
if (count == 0)
printk("no user tasks on cell %d\n",mpp_cid());
@@ -118,15 +129,19 @@ static void show_utasks(void)
static void show_otasks(void)
{
extern struct task_struct *task[];
+ struct task_struct *p;
int i;
int count=0;
extern int ap_current_uid;
- for (i=0;i<NR_TASKS;i++)
- if (task[i] && task[i]->uid == ap_current_uid) {
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if(p->uid == ap_current_uid) {
show_task(task[i]);
count++;
}
+ }
+ read_unlock(&tasklist_lock);
if (count == 0)
printk("no tasks on cell %d\n",mpp_cid());
diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c
index 021c1a2e5..84ef7f28e 100644
--- a/arch/sparc/ap1000/mpp.c
+++ b/arch/sparc/ap1000/mpp.c
@@ -66,6 +66,7 @@ int mpp_weight(struct task_struct *tsk)
if (block_parallel_tasks) return -1000;
+ /* XXX task[] fixme */
if (last_task && last_task != tsk->taskid && task[last_task] &&
!msc_switch_ok()) return -1000;
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index f73a52fb3..d3307e463 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $
+# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -28,7 +28,7 @@ else
CHECKASM_CC = $(CC)
endif
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S
index b93094919..fc6c4cead 100644
--- a/arch/sparc/kernel/etrap.S
+++ b/arch/sparc/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $
+/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $
* etrap.S: Sparc trap window preparation for entry into the
* Linux kernel.
*
@@ -129,15 +129,23 @@ tsetup_patch2:
trap_setup_from_user:
/* We can't use %curptr yet. */
LOAD_CURRENT(t_kstack, t_twinmask)
+
+ mov 1, %t_twinmask
+ sll %t_twinmask, (PAGE_SHIFT + 1), %t_twinmask
+ sub %t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask
+ add %t_kstack, %t_twinmask, %t_kstack
+
mov 1, %t_twinmask
- ld [%t_kstack + AOFF_task_saved_kernel_stack], %t_kstack
sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
/* Build pt_regs frame. */
STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
/* Clear current->tss.w_saved */
- LOAD_CURRENT(curptr, g1)
+ mov 1, %curptr
+ sll %curptr, (PAGE_SHIFT + 1), %curptr
+ sub %curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr
+ sub %t_kstack, %curptr, %curptr
st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved]
/* See if we are in the trap window. */
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index eea3528bf..90965e26e 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.81 1997/04/16 07:15:48 davem Exp $
+/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -393,12 +393,6 @@ C_LABEL(trapbase_cpu3):
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
- .globl C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack)
- .globl C_LABEL(cpu3_stack)
-C_LABEL(cpu0_stack): .skip 0x2000
-C_LABEL(cpu1_stack): .skip 0x2000
-C_LABEL(cpu2_stack): .skip 0x2000
-C_LABEL(cpu3_stack): .skip 0x2000
#endif
.skip 4096
@@ -742,6 +736,9 @@ go_to_highmem:
jmpl %g1, %g0
nop
+ /* This is to align init_task_union properly, be careful. -DaveM */
+ .align 8192
+
/* The code above should be at beginning and we have to take care about
* short jumps, as branching to .text.init section from .text is usually
* impossible */
@@ -986,12 +983,10 @@ sun4c_continue_boot:
/* Initialize the umask value for init_task just in case.
* But first make current_set[0] point to something useful.
*/
- set C_LABEL(init_task), %g6
+ set C_LABEL(init_task_union), %g6
set C_LABEL(current_set), %g2
st %g6, [%g2]
- set C_LABEL(bootup_kernel_stack), %g3
- st %g3, [%g6 + AOFF_task_kernel_stack_page]
st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask]
/* Compute NWINDOWS and stash it away. Now uses %wim trick explained
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
new file mode 100644
index 000000000..d0fc09346
--- /dev/null
+++ b/arch/sparc/kernel/init_task.c
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 70042857f..b22f008a1 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.72 1997/04/20 11:41:26 ecd Exp $
+/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 davem Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -313,8 +313,180 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
+#ifdef DEBUG_IRQLOCK
+
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count[cpu];
+
+ /* Are we the only one in an interrupt context? */
+ while (local_count != atomic_read(&global_irq_count)) {
+ /*
+ * No such luck. Now we need to release the lock,
+ * _and_ release our interrupt context, because
+ * otherwise we'd have dead-locks and live-locks
+ * and other fun things.
+ */
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+
+ /*
+ * Wait for everybody else to go away and release
+ * their things before trying to get the lock again.
+ */
+ for (;;) {
+ STUCK;
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ STUCK;
+ barrier();
+ } while (*((unsigned char *)&global_irq_lock));
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ /*
+ * Ok, we got the lock bit.
+ * But that's actually just the easy part.. Now
+ * we need to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu, where);
+
+ /*
+ * Finally.
+ */
+ global_irq_holder = cpu;
+ previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+ unsigned long where;
+
+ __asm__("mov %%i7, %0" : "=r" (where));
+ __cli();
+ get_irqlock(cpu, where);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ if(flags & 1) {
+ __global_cli();
+ } else {
+ /* release_irqlock() */
+ if(global_irq_holder == smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if(!(flags & 2))
+ __sti();
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
+#define VERBOSE_IRQLOCK_DEBUGGING
+
+void irq_enter(int cpu, int irq, void *_opaque)
+{
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ extern void smp_show_backtrace_all_cpus(void);
+#endif
+ int stuck = INIT_STUCK;
+
+ hardirq_enter(cpu);
+ barrier();
+ while (*((unsigned char *)&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder) {
+ struct pt_regs *regs = _opaque;
+ int sbh_cnt = atomic_read(&__sparc_bh_counter);
+ int globl_locked = *((unsigned char *)&global_irq_lock);
+ int globl_icount = atomic_read(&global_irq_count);
+ int local_count = local_irq_count[cpu];
+ unsigned long pc = regs->pc;
+
+ /* It is very important that we load the state variables
+ * before we do the first call to printk() as printk()
+ * could end up changing them...
+ */
+
+ printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled "
+ "interrupt at PC[%08lx]\n", cpu, pc);
+ printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n",
+ cpu, sbh_cnt, globl_locked, globl_icount, local_count);
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ printk("Performing backtrace on all cpus, write this down!\n");
+ smp_show_backtrace_all_cpus();
+#endif
+ break;
+ }
+ STUCK;
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+#endif /* DEBUG_IRQLOCK */
+
/* There has to be a better way. */
-/* XXX Must write faster version in irqlock.S -DaveM */
void synchronize_irq(void)
{
int cpu = smp_processor_id();
@@ -371,7 +543,7 @@ void handler_irq(int irq, struct pt_regs * regs)
if(irq < 10)
smp_irq_rotate(cpu);
#endif
- irq_enter(cpu, cpu_irq);
+ irq_enter(cpu, cpu_irq, regs);
action = *(cpu_irq + irq_action);
kstat.interrupts[cpu_irq]++;
do {
@@ -392,7 +564,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
int cpu = smp_processor_id();
disable_pil_irq(irq);
- irq_enter(cpu, irq);
+ irq_enter(cpu, irq, regs);
floppy_interrupt(irq, dev_id, regs);
irq_exit(cpu, irq);
enable_pil_irq(irq);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 96c57e963..1adc9e817 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $
+/* $Id: process.c,v 1.98 1997/05/14 20:44:54 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -41,6 +41,8 @@
extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
#ifndef __SMP__
#define SUN4C_FAULT_HIGH 100
@@ -192,6 +194,37 @@ void show_regwindow(struct reg_window *rw)
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
+static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
+
+void show_backtrace(void)
+{
+ struct reg_window *rw;
+ unsigned long flags;
+ unsigned long fp;
+ int cpu = smp_processor_id();
+
+ spin_lock_irqsave(&sparc_backtrace_lock, flags);
+ __asm__ __volatile__("mov %%i6, %0" : "=r" (fp));
+ rw = (struct reg_window *) fp;
+ while(rw) {
+ printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
+ "FP[%08lx] CALLER[%08lx]\n", cpu,
+ rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+ rw->ins[4], rw->ins[5],
+ rw->ins[6],
+ rw->ins[7]);
+ rw = (struct reg_window *) rw->ins[6];
+ }
+ spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
+}
+
+#ifdef __SMP__
+void smp_show_backtrace_all_cpus(void)
+{
+ xc0((smpfunc_t) show_backtrace);
+}
+#endif
+
void show_stackframe(struct sparc_stackf *sf)
{
unsigned long size;
@@ -441,12 +474,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if(regs->psr & PSR_PS)
stack_offset -= REGWIN_SZ;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
copy_regs(childregs, regs);
new_stack = (((struct reg_window *) childregs) - 1);
copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
- p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
+ p->tss.ksp = (unsigned long) new_stack;
#ifdef __SMP__
p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8);
p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL;
@@ -467,7 +500,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
- if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf *childstack;
struct sparc_stackf *parentstack;
@@ -475,9 +508,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
* This is a clone() call with supplied user stack.
* Set some valid stack frames to give to the child.
*/
- childstack = (struct sparc_stackf *)sp;
- parentstack = (struct sparc_stackf *)
- current->tss.kregs->u_regs[UREG_FP];
+ childstack = (struct sparc_stackf *) sp;
+ parentstack = (struct sparc_stackf *) regs->u_regs[UREG_FP];
#if 0
printk("clone: parent stack:\n");
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 647081eda..732b3006d 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -24,18 +24,6 @@
#define MAGIC_CONSTANT 0x80000000
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
/*
* This routine gets a long from any process space by following the page
* tables. NOTE! You should check that the long isn't on a page boundary,
@@ -53,7 +41,7 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -63,7 +51,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -73,7 +61,7 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
@@ -106,7 +94,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -116,7 +104,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -126,12 +114,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -533,7 +521,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
#endif
- if(!(child = get_task(pid))) {
+ if(!(child = find_task_by_pid(pid))) {
pt_error_return(regs, ESRCH);
goto out;
}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index f2af0b763..aa204db06 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.83 1997/04/01 02:21:49 davem Exp $
+/* $Id: setup.c,v 1.84 1997/05/08 17:45:16 davem Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,8 @@ void prom_sync_me(void)
#ifdef __SMP__
global_irq_holder = NO_PROC_ID;
- global_irq_lock = global_bh_lock = 0;
+ *((unsigned char *)&global_irq_lock) = 0;
+ *((unsigned char *)&global_bh_lock) = 0;
#endif
__save_and_cli(flags);
__asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 8a07ae0be..fd5fa634e 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.73 1997/04/16 05:56:05 davem Exp $
+/* $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -780,8 +780,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
+ lock_kernel();
if(current->binfmt->core_dump(signr, regs))
signr |= 0x80;
+ unlock_kernel();
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 6622f88f0..beef2df14 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -4,16 +4,18 @@
*/
#include <asm/head.h>
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/tasks.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
@@ -24,6 +26,9 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
#define IRQ_RESCHEDULE 13
#define IRQ_STOP_CPU 14
#define IRQ_CROSS_CALL 15
@@ -33,6 +38,9 @@ extern int linux_num_cpus;
extern void calibrate_delay(void);
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
@@ -118,16 +126,6 @@ void smp_store_cpu_info(int id)
cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */
}
-/*
- * Architecture specific routine called by the kernel just before init is
- * fired off. This allows the BP to have everything in order [we hope].
- * At the end of this all the AP's will hit the system scheduling and off
- * we go. Each AP will load the system gdt's and jump through the kernel
- * init into idle(). At this point the scheduler will one day take over
- * and give them jobs to do. smp_callin is a standard routine
- * we use to track CPU's as they power up.
- */
-
void smp_commence(void)
{
/*
@@ -144,7 +142,7 @@ static void smp_setup_percpu_timer(void);
void smp_callin(void)
{
- int cpuid = smp_processor_id();
+ int cpuid = hard_smp_processor_id();
local_flush_cache_all();
local_flush_tlb_all();
@@ -183,6 +181,25 @@ void smp_callin(void)
__sti();
}
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+
+/* Only broken Intel needs this, thus it should not even be referenced
+ * globally...
+ */
+void initialize_secondary(void)
+{
+}
+
+/* Activate a secondary processor. */
+int start_secondary(void *unused)
+{
+ trap_init();
+ init_IRQ();
+ smp_callin();
+ return cpu_idle(NULL);
+}
+
void cpu_panic(void)
{
printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
@@ -220,6 +237,7 @@ void smp_boot_cpus(void)
cpu_number_map[boot_cpu_id] = 0;
cpu_logical_map[0] = boot_cpu_id;
klock_info.akp = boot_cpu_id;
+ current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
smp_setup_percpu_timer();
@@ -233,10 +251,19 @@ void smp_boot_cpus(void)
if(cpu_present_map & (1 << i)) {
extern unsigned long sparc_cpu_startup;
unsigned long *entry = &sparc_cpu_startup;
+ struct task_struct *p;
int timeout;
+ /* Cook up an idler for this guy. */
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+
+ p = task[++cpucount];
+
+ p->processor = i;
+ current_set[i] = p;
+
/* See trampoline.S for details... */
- entry += ((i-1) * 6);
+ entry += ((i-1) * 3);
/* whirrr, whirrr, whirrrrrrrrr... */
printk("Starting CPU %d at %p\n", i, entry);
@@ -253,10 +280,10 @@ void smp_boot_cpus(void)
}
if(cpu_callin_map[i]) {
/* Another "Red Snapper". */
- cpucount++;
cpu_number_map[i] = i;
cpu_logical_map[i] = i;
} else {
+ cpucount--;
printk("Processor %d is stuck.\n", i);
}
}
@@ -364,26 +391,17 @@ struct smp_funcall {
unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
} ccall_info;
-/* Returns failure code if for example any of the cpu's failed to respond
- * within a certain timeout period.
- */
-
-#define CCALL_TIMEOUT 5000000 /* enough for initial testing */
-
static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
/* Cross calls must be serialized, at least currently. */
void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
- unsigned long me = smp_processor_id();
- unsigned long flags, mask;
- int i, timeout;
-
if(smp_processors_ready) {
- __save_flags(flags);
- __cli();
- spin_lock(&cross_call_lock);
+ register int ncpus = smp_num_cpus;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cross_call_lock, flags);
/* Init function glue. */
ccall_info.func = func;
@@ -393,56 +411,47 @@ void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
ccall_info.arg4 = arg4;
ccall_info.arg5 = arg5;
- /* Init receive/complete mapping. */
- for(i = 0; i < smp_num_cpus; i++) {
- ccall_info.processors_in[i] = 0;
- ccall_info.processors_out[i] = 0;
+ /* Init receive/complete mapping, plus fire the IPI's off. */
+ {
+ register void (*send_ipi)(int,int) = set_cpu_int;
+ register unsigned long mask;
+ register int i;
+
+ mask = (cpu_present_map & ~(1 << smp_processor_id()));
+ for(i = 0; i < ncpus; i++) {
+ if(mask & (1 << i)) {
+ ccall_info.processors_in[i] = 0;
+ ccall_info.processors_out[i] = 0;
+ send_ipi(mid_xlate[i], IRQ_CROSS_CALL);
+ } else {
+ ccall_info.processors_in[i] = 1;
+ ccall_info.processors_out[i] = 1;
+ }
+ }
}
- ccall_info.processors_in[me] = 1;
- ccall_info.processors_out[me] = 1;
- /* Fire it off. */
- mask = (cpu_present_map & ~(1 << me));
- for(i = 0; i < 4; i++) {
- if(mask & (1 << i))
- set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
- }
+ /* First, run local copy. */
+ func(arg1, arg2, arg3, arg4, arg5);
- /* For debugging purposes right now we can timeout
- * on both callin and callexit.
- */
- timeout = CCALL_TIMEOUT;
- for(i = 0; i < smp_num_cpus; i++) {
- while(!ccall_info.processors_in[i] && timeout-- > 0)
- barrier();
- if(!ccall_info.processors_in[i])
- goto procs_time_out;
- }
+ {
+ register int i;
- /* Run local copy. */
- func(arg1, arg2, arg3, arg4, arg5);
+ i = 0;
+ do {
+ while(!ccall_info.processors_in[i])
+ barrier();
+ } while(++i < ncpus);
- /* Spin on proc dispersion. */
- timeout = CCALL_TIMEOUT;
- for(i = 0; i < smp_num_cpus; i++) {
- while(!ccall_info.processors_out[i] && timeout-- > 0)
- barrier();
- if(!ccall_info.processors_out[i])
- goto procs_time_out;
+ i = 0;
+ do {
+ while(!ccall_info.processors_out[i])
+ barrier();
+ } while(++i < ncpus);
}
- spin_unlock(&cross_call_lock);
- __restore_flags(flags);
- return; /* made it... */
-
-procs_time_out:
- printk("smp: Wheee, penguin drops off the bus\n");
- spin_unlock(&cross_call_lock);
- __restore_flags(flags);
- return; /* why me... why me... */
- }
- /* Just need to run local copy. */
- func(arg1, arg2, arg3, arg4, arg5);
+ spin_unlock_irqrestore(&cross_call_lock, flags);
+ } else
+ func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
}
void smp_flush_cache_all(void)
@@ -453,43 +462,98 @@ void smp_flush_tlb_all(void)
void smp_flush_cache_mm(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT)
- xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_mm(mm);
+ else
+ xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm);
+ }
}
void smp_flush_tlb_mm(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT)
- xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id())) {
+ local_flush_tlb_mm(mm);
+ } else {
+ xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm);
+ if(mm->count == 1 && current->mm == mm)
+ mm->cpu_vm_mask = (1 << smp_processor_id());
+ }
+ }
}
void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- if(mm->context != NO_CONTEXT)
- xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm,
- start, end);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_range(mm, start, end);
+ else
+ xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm,
+ start, end);
+ }
}
void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- if(mm->context != NO_CONTEXT)
- xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm,
- start, end);
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_tlb_range(mm, start, end);
+ else
+ xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm,
+ start, end);
+ }
}
void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{ xc2((smpfunc_t) local_flush_cache_page, (unsigned long) vma, page); }
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_cache_page(vma, page);
+ else
+ xc2((smpfunc_t) local_flush_cache_page,
+ (unsigned long) vma, page);
+ }
+}
void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page); }
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT) {
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_tlb_page(vma, page);
+ else
+ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page);
+ }
+}
void smp_flush_page_to_ram(unsigned long page)
-{ xc1((smpfunc_t) local_flush_page_to_ram, page); }
+{
+ /* Current theory is that those who call this are the one's
+ * who have just dirtied their cache with the pages contents
+ * in kernel space, therefore we only run this on local cpu.
+ *
+ * XXX This experiment failed, research further... -DaveM
+ */
+#if 1
+ xc1((smpfunc_t) local_flush_page_to_ram, page);
+#else
+ local_flush_page_to_ram(page);
+#endif
+}
void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr); }
+{
+ if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+ local_flush_sig_insns(mm, insn_addr);
+ else
+ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr);
+}
/* Reschedule call back. */
void smp_reschedule_irq(void)
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 645aafb35..38896ab22 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.56 1997/04/18 05:44:35 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.59 1997/05/08 17:45:20 davem Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -38,6 +38,7 @@
#include <asm/dma.h>
#endif
#include <asm/a.out.h>
+#include <asm/spinlock.h>
struct poll {
int fd;
@@ -50,9 +51,9 @@ extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void __copy_1page(void *, const void *);
+extern void (*__copy_1page)(void *, const void *);
extern void __memmove(void *, const void *, __kernel_size_t);
-extern void *bzero_1page(void *);
+extern void (*bzero_1page)(void *);
extern void *__bzero(void *, size_t);
extern void *__memscan_zero(void *, size_t);
extern void *__memscan_generic(void *, int, size_t);
@@ -87,17 +88,47 @@ EXPORT_SYMBOL(klock_info);
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
+#ifdef SPIN_LOCK_DEBUG
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_spin_trylock);
+EXPORT_SYMBOL(_spin_lock_irq);
+EXPORT_SYMBOL(_spin_unlock_irq);
+EXPORT_SYMBOL(_spin_lock_irqsave);
+EXPORT_SYMBOL(_spin_unlock_irqrestore);
+EXPORT_SYMBOL(_read_lock);
+EXPORT_SYMBOL(_read_unlock);
+EXPORT_SYMBOL(_read_lock_irq);
+EXPORT_SYMBOL(_read_unlock_irq);
+EXPORT_SYMBOL(_read_lock_irqsave);
+EXPORT_SYMBOL(_read_unlock_irqrestore);
+EXPORT_SYMBOL(_write_lock);
+EXPORT_SYMBOL(_write_unlock);
+EXPORT_SYMBOL(_write_lock_irq);
+EXPORT_SYMBOL(_write_unlock_irq);
+EXPORT_SYMBOL(_write_lock_irqsave);
+EXPORT_SYMBOL(_write_unlock_irqrestore);
+#else
EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
+#endif
EXPORT_SYMBOL(__sparc_bh_counter);
#ifdef __SMP__
+#ifdef DEBUG_IRQLOCK
+EXPORT_SYMBOL(irq_enter);
+EXPORT_SYMBOL(irq_exit);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_cli);
+#else
EXPORT_SYMBOL_PRIVATE(_irq_enter);
EXPORT_SYMBOL_PRIVATE(_irq_exit);
EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
EXPORT_SYMBOL_PRIVATE(_global_sti);
EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
+#endif
EXPORT_SYMBOL(page_offset);
EXPORT_SYMBOL(stack_top);
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 5f5b19504..3fafe7f9c 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.78 1997/04/16 05:56:12 davem Exp $
+/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
#include <linux/resource.h>
#include <linux/ipc.h>
#include <linux/shm.h>
+#include <linux/msg.h>
#include <linux/sem.h>
#include <linux/signal.h>
#include <linux/uio.h>
@@ -1031,7 +1032,48 @@ asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2,
unlock_kernel();
return ret;
}
-
+
+extern asmlinkage int sys_msgget (key_t key, int msgflg);
+extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp,
+ size_t msgsz, long msgtyp, int msgflg);
+extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp,
+ size_t msgsz, int msgflg);
+extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4)
+{
+ struct sparc_stackf *sp;
+ unsigned long arg5;
+ int rval;
+
+ lock_kernel();
+ switch(op) {
+ case 0:
+ rval = sys_msgget((key_t)arg1, (int)arg2);
+ break;
+ case 1:
+ rval = sys_msgctl((int)arg1, (int)arg2,
+ (struct msqid_ds *)arg3);
+ break;
+ case 2:
+ sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP];
+ arg5 = sp->xxargs[0];
+ rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2,
+ (size_t)arg3, (long)arg4, (int)arg5);
+ break;
+ case 3:
+ rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2,
+ (size_t)arg3, (int)arg4);
+ break;
+ default:
+ rval = -EINVAL;
+ break;
+ }
+ unlock_kernel();
+ return rval;
+}
+
extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
extern asmlinkage int sys_shmdt (char *shmaddr);
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 61b41056b..a166e3490 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.60 1997/04/19 08:52:15 jj Exp $
+/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -106,15 +106,26 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
/* "We are the Knights of the Forest of Ni!!" */
- .long C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall)
- .long C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam)
- .long C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min)
- .long C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep)
+ .long C_LABEL(sys_mlock)
+ .long C_LABEL(sys_munlock)
+ .long C_LABEL(sys_mlockall)
+/*240*/ .long C_LABEL(sys_munlockall)
+ .long C_LABEL(sys_sched_setparam)
+ .long C_LABEL(sys_sched_getparam)
+ .long C_LABEL(sys_sched_setscheduler)
+ .long C_LABEL(sys_sched_getscheduler)
+/*245*/ .long C_LABEL(sys_sched_yield)
+ .long C_LABEL(sys_sched_get_priority_max)
+ .long C_LABEL(sys_sched_get_priority_min)
+ .long C_LABEL(sys_sched_rr_get_interval)
+ .long C_LABEL(sys_nanosleep)
/*250*/ .long C_LABEL(sys_mremap)
.long C_LABEL(sys_sysctl)
- .long C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nfsservctl)
- .long C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_getsid)
+ .long C_LABEL(sys_fdatasync)
+ .long C_LABEL(sys_nfsservctl)
+/*255*/ .long C_LABEL(sys_aplib)
+ .long C_LABEL(sys_nis_syscall)
/* Now the SunOS syscall table. */
@@ -179,7 +190,7 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
.long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
- .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
+ .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
.long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
index bea6336c5..03fe3cff9 100644
--- a/arch/sparc/kernel/tadpole.c
+++ b/arch/sparc/kernel/tadpole.c
@@ -4,6 +4,8 @@
*/
#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
#include <asm/asi.h>
#include <asm/oplib.h>
diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S
index c59a2531a..9ee5bd14a 100644
--- a/arch/sparc/kernel/trampoline.S
+++ b/arch/sparc/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $
+/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $
* trampoline.S: SMP cpu boot-up trampoline code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
#include <asm/cprefix.h>
#include <asm/head.h>
#include <asm/psr.h>
+#include <asm/page.h>
#include <asm/asi.h>
#include <asm/ptrace.h>
#include <asm/vaddrs.h>
@@ -25,27 +26,18 @@
C_LABEL(sparc_cpu_startup):
cpu1_startup:
sethi %hi(C_LABEL(trapbase_cpu1)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3
- sethi %hi(C_LABEL(cpu1_stack)), %g2
- or %g2, %lo(C_LABEL(cpu1_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3
cpu2_startup:
sethi %hi(C_LABEL(trapbase_cpu2)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3
- sethi %hi(C_LABEL(cpu2_stack)), %g2
- or %g2, %lo(C_LABEL(cpu2_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3
cpu3_startup:
sethi %hi(C_LABEL(trapbase_cpu3)), %g3
- or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3
- sethi %hi(C_LABEL(cpu3_stack)), %g2
- or %g2, %lo(C_LABEL(cpu3_stack)), %g2
b 1f
- nop
+ or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3
1:
/* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
@@ -62,14 +54,16 @@ cpu3_startup:
wr %g3, 0x0, %tbr
WRITE_PAUSE
- /* Give ourselves a stack. */
- set 0x2000, %g5
- add %g2, %g5, %g2 ! end of stack
- sub %g2, REGWIN_SZ, %sp
- mov 0, %fp
+ /* Give ourselves a stack and curptr. */
+ set C_LABEL(current_set), %g5
+ srl %g3, 10, %g4
+ and %g4, 0xc, %g4
+ ld [%g5 + %g4], %g6
- /* Set up curptr. */
- set C_LABEL(init_task), %g6
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, REGWIN_SZ, %sp
+ add %g6, %sp, %sp
/* Turn on traps (PSR_ET). */
rd %psr, %g1
diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S
index bad0088f4..890676bfb 100644
--- a/arch/sparc/kernel/wof.S
+++ b/arch/sparc/kernel/wof.S
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $
+/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $
* wof.S: Sparc window overflow handler.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -234,15 +234,20 @@ spwin_user_stack_is_bolixed:
spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs
st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask]
- /* Jump onto kernel stack for this process... */
- ld [%curptr + AOFF_task_saved_kernel_stack], %sp
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+ add %curptr, %sp, %sp
/* Restore the saved globals and build a pt_regs frame. */
mov %saved_g5, %g5
- mov %g6, %l4
mov %saved_g6, %g6
STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
- mov %l4, %g6
+
+ mov 1, %g6
+ sll %g6, (PAGE_SHIFT + 1), %g6
+ sub %g6, (TRACEREG_SZ + REGWIN_SZ), %g6
+ sub %sp, %g6, %g6
/* Turn on traps and call c-code to deal with it. */
wr %t_psr, PSR_ET, %psr
diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S
index 7550dd627..cb407aa69 100644
--- a/arch/sparc/kernel/wuf.S
+++ b/arch/sparc/kernel/wuf.S
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $
+/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $
* wuf.S: Window underflow trap handler for the Sparc.
*
* Copyright (C) 1995 David S. Miller
@@ -145,14 +145,17 @@ fwin_user_stack_is_bolixed:
* to the trap window and call c-code to deal with this.
*/
LOAD_CURRENT(l4, l5)
- ld [%l4 + AOFF_task_saved_kernel_stack], %l5
+
+ mov 1, %l5
+ sll %l5, (PAGE_SHIFT + 1), %l5
+ sub %l5, (TRACEREG_SZ + REGWIN_SZ), %l5
+ add %l4, %l5, %l5
/* Store globals into pt_regs frame. */
STORE_PT_GLOBALS(l5)
STORE_PT_YREG(l5, g3)
- /* Save kernel %sp in global while we change windows. */
- mov %l5, %g2
+ /* Save current in a global while we change windows. */
mov %l4, %curptr
save %g0, %g0, %g0
@@ -166,7 +169,10 @@ fwin_user_stack_is_bolixed:
/* LOCATION: Window 'T' */
- mov %g2, %sp /* Jump onto kernel %sp being held */
+ mov 1, %sp
+ sll %sp, (PAGE_SHIFT + 1), %sp
+ sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+ add %curptr, %sp, %sp
/* Build rest of pt_regs. */
STORE_PT_INS(sp)
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 1bf49bf13..cefe7a851 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -1,13 +1,11 @@
-# $Id: Makefile,v 1.23 1997/04/18 05:44:39 davem Exp $
+# $Id: Makefile,v 1.24 1997/05/08 17:45:26 davem Exp $
# Makefile for Sparc library files..
#
-CFLAGS := $(CFLAGS) -ansi
-
OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
- copy_user.o locks.o atomic.o bitops.o
+ copy_user.o locks.o atomic.o bitops.o debuglocks.o
ifdef SMP
OBJS += irqlock.o
diff --git a/arch/sparc/lib/blockops.S b/arch/sparc/lib/blockops.S
index f8a9e80df..c11ab1b20 100644
--- a/arch/sparc/lib/blockops.S
+++ b/arch/sparc/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1996/09/24 05:22:56 davem Exp $
+/* $Id: blockops.S,v 1.6 1997/05/03 02:01:54 davem Exp $
* blockops.S: Common block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -46,25 +46,7 @@
.text
.align 4
- .globl C_LABEL(bzero_2page), C_LABEL(bzero_1page)
-C_LABEL(bzero_2page):
- /* %o0 = buf */
- or %g0, %g0, %g1
- or %o0, %g0, %o1
- or %g0, 0x20, %g2
-1:
- BLAST_BLOCK(%o0, 0x00)
- BLAST_BLOCK(%o0, 0x40)
- BLAST_BLOCK(%o0, 0x80)
- BLAST_BLOCK(%o0, 0xc0)
- subcc %g2, 1, %g2
- bne 1b
- add %o0, 0x100, %o0
-
- retl
- mov %o1, %o0
-
-C_LABEL(bzero_1page):
+generic_bzero_1page:
/* %o0 = buf */
or %g0, %g0, %g1
or %o0, %g0, %o1
@@ -79,10 +61,9 @@ C_LABEL(bzero_1page):
add %o0, 0x100, %o0
retl
- mov %o1, %o0
+ nop
- .globl C_LABEL(__copy_1page)
-C_LABEL(__copy_1page):
+__generic_copy_1page:
/* %o0 = dst, %o1 = src */
or %g0, 0x10, %g1
1:
@@ -101,3 +82,9 @@ C_LABEL(__copy_1page):
retl
nop
+
+ .data
+ .align 4
+ .globl C_LABEL(bzero_1page), C_LABEL(__copy_1page)
+C_LABEL(bzero_1page): .word generic_bzero_1page
+C_LABEL(__copy_1page): .word __generic_copy_1page
diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c
new file mode 100644
index 000000000..006cba5a8
--- /dev/null
+++ b/arch/sparc/lib/debuglocks.c
@@ -0,0 +1,463 @@
+/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $
+ * debuglocks.c: Debugging versions of SMP locking primitives.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/psr.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
+#ifdef SPIN_LOCK_DEBUG
+
+/* Some notes on how these debugging routines work. When a lock is acquired
+ * an extra debugging member lock->owner_pc is set to the caller of the lock
+ * acquisition routine. Right before releasing a lock, the debugging program
+ * counter is cleared to zero.
+ *
+ * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU
+ * number of the owner in the lowest two bits.
+ */
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _spin_lock(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+int _spin_trylock(spinlock_t *lock)
+{
+ unsigned long val;
+ unsigned long caller;
+ int cpu = smp_processor_id();
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(!val) {
+ /* We got it, record our identity for debugging. */
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+ }
+ return val == 0;
+}
+
+void _spin_unlock(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _spin_lock_irq(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __cli();
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+void _spin_unlock_irq(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller macro does __save_and_cli(flags) for us. */
+void _spin_lock_irqsave(spinlock_t *lock)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+again:
+ __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
+ if(val) {
+ while(lock->lock) {
+ STUCK;
+ barrier();
+ }
+ goto again;
+ }
+ lock->owner_pc = (cpu & 3) | (caller & ~3);
+}
+
+void _spin_unlock_irqrestore(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_lock(rwlock_t *rw)
+{
+ unsigned long flags;
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+ __restore_flags(flags);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock(rwlock_t *rw)
+{
+ unsigned long flags, val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+ __restore_flags(flags);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _write_lock(rwlock_t *rw)
+{
+ unsigned long flags, val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __save_and_cli(flags);
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_lock_irq(rwlock_t *rw)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __cli();
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock_irq(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _write_lock_irq(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ __cli();
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock_irq(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+ __sti();
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller does __save_and_cli(flags) for us. */
+void _read_lock_irqsave(rwlock_t *rw)
+{
+ unsigned long caller;
+ unsigned long val;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))++;
+ barrier();
+ (*(((unsigned short *)&rw->lock)+1)) = 0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+void _read_unlock_irqrestore(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+clock_again:
+ __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff00) {
+ STUCK;
+ barrier();
+ }
+ goto clock_again;
+ }
+ (*((unsigned short *)&rw->lock))--;
+ barrier();
+ (*(((unsigned char *)&rw->lock)+2))=0;
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+
+/* Caller does __save_and_cli(flags) for us. */
+void _write_lock_irqsave(rwlock_t *rw)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+ int stuck = INIT_STUCK;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
+ if(val) {
+ while(rw->lock & 0xff) {
+ STUCK;
+ barrier();
+ }
+ goto wlock_again;
+ }
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
+ while(rw->lock & ~0xff) {
+ STUCK;
+ barrier();
+ }
+}
+
+void _write_unlock_irqrestore(rwlock_t *rw)
+{
+ rw->owner_pc = 0;
+ barrier();
+ rw->lock = 0;
+}
+
+#endif /* SPIN_LOCK_DEBUG */
diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S
index db7dd26c3..23194e723 100644
--- a/arch/sparc/lib/irqlock.S
+++ b/arch/sparc/lib/irqlock.S
@@ -1,4 +1,4 @@
-/* $Id: irqlock.S,v 1.2 1997/04/19 04:33:37 davem Exp $
+/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $
* irqlock.S: High performance IRQ global locking and interrupt entry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 4ae57f18f..f7b9b367c 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.24 1997/04/20 14:11:49 ecd Exp $
+# $Id: Makefile,v 1.25 1997/05/03 05:09:11 davem Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -9,12 +9,30 @@
O_TARGET := mm.o
O_OBJS := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \
- loadmmu.o generic.o asyncd.o extable.o
+ tsunami.o loadmmu.o generic.o asyncd.o extable.o
include $(TOPDIR)/Rules.make
+ifdef SMP
+
+hypersparc.o: hypersparc.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
+
+viking.o: viking.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
+
+tsunami.o: tsunami.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
+
+else
+
hypersparc.o: hypersparc.S
$(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S
viking.o: viking.S
$(CC) -D__ASSEMBLY__ -ansi -c -o viking.o viking.S
+
+tsunami.o: tsunami.S
+ $(CC) -D__ASSEMBLY__ -ansi -c -o tsunami.o tsunami.S
+
+endif
diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c
index 5d9d476a5..46635db97 100644
--- a/arch/sparc/mm/asyncd.c
+++ b/arch/sparc/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.9 1996/12/18 06:43:22 tridge Exp $
+/* $Id: asyncd.c,v 1.10 1997/05/15 21:14:24 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -153,7 +153,7 @@ static int fault_in_page(int taskid,
if(!pte)
goto no_memory;
if(!pte_present(*pte)) {
- do_no_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
goto finish_up;
}
set_pte(pte, pte_mkyoung(*pte));
@@ -165,12 +165,11 @@ static int fault_in_page(int taskid,
flush_tlb_page(vma, address);
goto finish_up;
}
- do_wp_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
/* Fall through for do_wp_page */
finish_up:
stats.success++;
- update_mmu_cache(vma, address, *pte);
return 0;
no_memory:
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index cfac6bcc2..0d6490860 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.91 1997/03/18 17:56:00 jj Exp $
+/* $Id: fault.c,v 1.92 1997/05/15 21:14:21 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -229,7 +229,7 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
goto out;
/*
@@ -370,7 +370,7 @@ good_area:
else
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
return;
bad_area:
diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S
index 4e5a19301..62e2022e0 100644
--- a/arch/sparc/mm/hypersparc.S
+++ b/arch/sparc/mm/hypersparc.S
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.4 1997/04/19 04:33:39 davem Exp $
+/* $Id: hypersparc.S,v 1.7 1997/05/03 05:09:12 davem Exp $
* hypersparc.S: High speed Hypersparc mmu/cache operations.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -79,7 +79,7 @@ hypersparc_flush_cache_mm:
sta %g0, [%o0 + %o4] ASI_M_FLUSH_USER
hypersparc_flush_cache_mm_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE ! hyper_flush_whole_icache
+ nop
/* The things we do for performance... */
hypersparc_flush_cache_range:
@@ -126,7 +126,7 @@ hypersparc_flush_cache_range:
bne 1b
sta %g0, [%o3 + %g5] ASI_M_FLUSH_USER
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
/* Below our threshold, flush one page at a time. */
0:
@@ -166,7 +166,7 @@ hypersparc_flush_cache_range:
sta %o3, [%g7] ASI_M_MMUREGS
hypersparc_flush_cache_range_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
/* HyperSparc requires a valid mapping where we are about to flush
* in order to check for a physical tag match during the flush.
@@ -221,12 +221,12 @@ hypersparc_flush_cache_page:
sta %o2, [%g4] ASI_M_MMUREGS
hypersparc_flush_cache_page_out:
retl
- sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+ nop
hypersparc_flush_sig_insns:
- flush %o2
+ flush %o1
retl
- flush %o2 + 4
+ flush %o1 + 4
/* HyperSparc is copy-back. */
hypersparc_flush_page_to_ram:
@@ -289,7 +289,7 @@ hypersparc_flush_tlb_mm:
cmp %o1, -1
be hypersparc_flush_tlb_mm_out
#endif
- mov 0x300, %g2
+ mov 0x300, %g2
sta %o1, [%g1] ASI_M_MMUREGS
sta %g0, [%g2] ASI_M_FLUSH_PROBE
hypersparc_flush_tlb_mm_out:
@@ -304,7 +304,7 @@ hypersparc_flush_tlb_range:
cmp %o3, -1
be hypersparc_flush_tlb_range_out
#endif
- srl %o1, SRMMU_PGDIR_SHIFT, %o1
+ srl %o1, SRMMU_PGDIR_SHIFT, %o1
sta %o3, [%g1] ASI_M_MMUREGS
sll %o1, SRMMU_PGDIR_SHIFT, %o1
sethi %hi(1 << SRMMU_PGDIR_SHIFT), %o4
@@ -324,13 +324,67 @@ hypersparc_flush_tlb_page:
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
- lda [%g1] ASI_M_MMUREGS, %g5
#ifndef __SMP__
cmp %o3, -1
be hypersparc_flush_tlb_page_out
#endif
+ lda [%g1] ASI_M_MMUREGS, %g5
sta %o3, [%g1] ASI_M_MMUREGS
sta %g0, [%o1] ASI_M_FLUSH_PROBE
hypersparc_flush_tlb_page_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+
+ /* High speed page clear/copy. */
+ .globl hypersparc_bzero_1page, hypersparc_copy_1page
+hypersparc_bzero_1page:
+ clr %g1
+ mov 32, %g2
+ add %g2, %g2, %g3
+ add %g2, %g3, %g4
+ add %g2, %g4, %g5
+ add %g2, %g5, %g7
+ add %g2, %g7, %o2
+ add %g2, %o2, %o3
+ mov 16, %o1
+1:
+ stda %g0, [%o0 + %g0] ASI_M_BFILL
+ stda %g0, [%o0 + %g2] ASI_M_BFILL
+ stda %g0, [%o0 + %g3] ASI_M_BFILL
+ stda %g0, [%o0 + %g4] ASI_M_BFILL
+ stda %g0, [%o0 + %g5] ASI_M_BFILL
+ stda %g0, [%o0 + %g7] ASI_M_BFILL
+ stda %g0, [%o0 + %o2] ASI_M_BFILL
+ stda %g0, [%o0 + %o3] ASI_M_BFILL
+ subcc %o1, 1, %o1
+ bne 1b
+ add %o0, 256, %o0
+
+ retl
+ nop
+
+hypersparc_copy_1page:
+ sub %o1, %o0, %o2 ! difference
+ mov 16, %g1
+1:
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ add %o0, 32, %o0
+ sta %o0, [%o0 + %o2] ASI_M_BCOPY
+ subcc %g1, 1, %g1
+ bne 1b
+ add %o0, 32, %o0
+
+ retl
+ nop
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 9d3afdbdf..b04064efb 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.136 1997/04/20 14:11:51 ecd Exp $
+/* $Id: srmmu.c,v 1.146 1997/05/18 21:11:09 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -77,12 +77,20 @@ ctxd_t *srmmu_context_table;
/* Don't change this without changing access to this
* in arch/sparc/mm/viking.S
*/
-struct srmmu_trans {
+static struct srmmu_trans {
unsigned long vbase;
unsigned long pbase;
unsigned long size;
} srmmu_map[SPARC_PHYS_BANKS];
+#define SRMMU_HASHSZ 256
+
+/* Not static, viking.S uses it. */
+struct srmmu_trans *srmmu_v2p_hash[SRMMU_HASHSZ];
+static struct srmmu_trans *srmmu_p2v_hash[SRMMU_HASHSZ];
+
+#define srmmu_ahashfn(addr) ((addr) >> 24)
+
static int viking_mxcc_present = 0;
void srmmu_frob_mem_map(unsigned long start_mem)
@@ -113,31 +121,26 @@ void srmmu_frob_mem_map(unsigned long start_mem)
/* Physical memory can be _very_ non-contiguous on the sun4m, especially
* the SS10/20 class machines and with the latest openprom revisions.
- * So we have to crunch the free page pool.
+ * So we have to do a quick lookup.
*/
static inline unsigned long srmmu_v2p(unsigned long vaddr)
{
- int i;
+ struct srmmu_trans *tp = srmmu_v2p_hash[srmmu_ahashfn(vaddr)];
- for(i=0; srmmu_map[i].size != 0; i++) {
- if(srmmu_map[i].vbase <= vaddr &&
- (srmmu_map[i].vbase + srmmu_map[i].size > vaddr)) {
- return (vaddr - srmmu_map[i].vbase) + srmmu_map[i].pbase;
- }
- }
- return 0xffffffffUL;
+ if(tp)
+ return (vaddr - tp->vbase + tp->pbase);
+ else
+ return 0xffffffffUL;
}
static inline unsigned long srmmu_p2v(unsigned long paddr)
{
- int i;
+ struct srmmu_trans *tp = srmmu_p2v_hash[srmmu_ahashfn(paddr)];
- for(i=0; srmmu_map[i].size != 0; i++) {
- if(srmmu_map[i].pbase <= paddr &&
- (srmmu_map[i].pbase + srmmu_map[i].size > paddr))
- return (paddr - srmmu_map[i].pbase) + srmmu_map[i].vbase;
- }
- return 0xffffffffUL;
+ if(tp)
+ return (paddr - tp->pbase + tp->vbase);
+ else
+ return 0xffffffffUL;
}
/* In general all page table modifications should use the V8 atomic
@@ -659,27 +662,6 @@ static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
srmmu_set_entry(ptep, pte_val(pteval));
}
-static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
-{
- unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
-
- srmmu_set_entry(ptep, pte_val(pteval));
- __asm__ __volatile__("
- lda [%0] %2, %%g4
- orcc %%g4, 0x0, %%g0
- be 2f
- sethi %%hi(%7), %%g5
-1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page
- bne 1b
- sta %%g0, [%1 + %%g5] %3
- lda [%4] %5, %%g0
-2:" : /* no outputs */
- : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
- "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
- "r" (vac_line_size), "i" (PAGE_SIZE)
- : "g4", "g5", "cc");
-}
-
static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
{
register unsigned long a, b, c, d, e, f, g;
@@ -860,134 +842,27 @@ static void srmmu_unlockarea(char *vaddr, unsigned long len)
*/
struct task_struct *srmmu_alloc_task_struct(void)
{
- return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
-}
-
-unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
-
- if(!kstk)
- kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
-
- return kstk;
+ return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0);
}
static void srmmu_free_task_struct(struct task_struct *tsk)
{
- kfree(tsk);
-}
-
-static void srmmu_free_kernel_stack(unsigned long stack)
-{
- if(stack < VMALLOC_START)
- free_pages(stack, 1);
- else
- vfree((char *)stack);
-}
-
-/* Tsunami flushes. It's page level tlb invalidation is not very
- * useful at all, you must be in the context that page exists in to
- * get a match.
- */
-static void tsunami_flush_cache_all(void)
-{
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
-}
-
-static void tsunami_flush_cache_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-static void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-static void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- FLUSH_BEGIN(vma->vm_mm)
- flush_user_windows();
- tsunami_flush_icache();
- tsunami_flush_dcache();
- FLUSH_END
-}
-
-/* Tsunami does not have a Copy-back style virtual cache. */
-static void tsunami_flush_page_to_ram(unsigned long page)
-{
-}
-
-/* However, Tsunami is not IO coherent. */
-static void tsunami_flush_page_for_dma(unsigned long page)
-{
- tsunami_flush_icache();
- tsunami_flush_dcache();
-}
-
-/* Tsunami has harvard style split I/D caches which do not snoop each other,
- * so we have to flush on-stack sig insns. Only the icache need be flushed
- * since the Tsunami has a write-through data cache.
- */
-static void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
- tsunami_flush_icache();
-}
-
-static void tsunami_flush_chunk(unsigned long chunk)
-{
+ free_pages((unsigned long)tsk, 1);
}
-static void tsunami_flush_tlb_all(void)
-{
- srmmu_flush_whole_tlb();
- module_stats.invall++;
-}
-
-static void tsunami_flush_tlb_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invmm++;
- FLUSH_END
-}
-
-static void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invrnge++;
- FLUSH_END
-}
-
-static void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
-
- FLUSH_BEGIN(mm)
- __asm__ __volatile__("
- lda [%0] %3, %%g5
- sta %1, [%0] %3
- sta %%g0, [%2] %4
- sta %%g5, [%0] %3"
- : /* no outputs */
- : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK),
- "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
- : "g5");
- module_stats.invpg++;
- FLUSH_END
-}
+/* tsunami.S */
+extern void tsunami_flush_cache_all(void);
+extern void tsunami_flush_cache_mm(struct mm_struct *mm);
+extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void tsunami_flush_page_to_ram(unsigned long page);
+extern void tsunami_flush_page_for_dma(unsigned long page);
+extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void tsunami_flush_chunk(unsigned long chunk);
+extern void tsunami_flush_tlb_all(void);
+extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
+extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
/* Swift flushes. It has the recommended SRMMU specification flushing
* facilities, so we can do things in a more fine grained fashion than we
@@ -1364,18 +1239,31 @@ extern void hypersparc_flush_tlb_all(void);
extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void hypersparc_bzero_1page(void *);
+extern void hypersparc_copy_1page(void *, const void *);
+
+static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
+{
+ unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
+
+ srmmu_set_entry(ptep, pte_val(pteval));
+ hypersparc_flush_page_to_ram(page);
+}
static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
{
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
hyper_flush_whole_icache();
- set_pte((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
}
static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
{
unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
- hypersparc_flush_page_to_ram(page);
+ if(pgdp != swapper_pg_dir)
+ hypersparc_flush_page_to_ram(page);
+
if(tsk->mm->context != NO_CONTEXT) {
flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
@@ -1429,26 +1317,29 @@ static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
static void hypersparc_switch_to_context(struct task_struct *tsk)
{
- hyper_flush_whole_icache();
if(tsk->mm->context == NO_CONTEXT) {
+ ctxd_t *ctxp;
+
alloc_context(tsk->mm);
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
- flush_tlb_mm(tsk->mm);
+ ctxp = &srmmu_context_table[tsk->mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
}
+ hyper_flush_whole_icache();
srmmu_set_context(tsk->mm->context);
}
static void hypersparc_init_new_context(struct mm_struct *mm)
{
- hyper_flush_whole_icache();
+ ctxd_t *ctxp;
alloc_context(mm);
- flush_cache_mm(mm);
- ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
- flush_tlb_mm(mm);
+ ctxp = &srmmu_context_table[mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
+ hyper_flush_whole_icache();
if(mm == current->mm)
srmmu_set_context(mm->context);
}
@@ -2150,6 +2041,32 @@ check_and_return:
MKTRACE(("success\n"));
init_task.mm->mmap->vm_start = page_offset = low_base;
stack_top = page_offset - PAGE_SIZE;
+#if 1
+ for(entry = 0; srmmu_map[entry].size; entry++) {
+ printk("[%d]: v[%08lx,%08lx](%lx) p[%08lx]\n", entry,
+ srmmu_map[entry].vbase,
+ srmmu_map[entry].vbase + srmmu_map[entry].size,
+ srmmu_map[entry].size,
+ srmmu_map[entry].pbase);
+ }
+#endif
+
+ /* Now setup the p2v/v2p hash tables. */
+ for(entry = 0; entry < SRMMU_HASHSZ; entry++)
+ srmmu_v2p_hash[entry] = srmmu_p2v_hash[entry] = NULL;
+ for(entry = 0; srmmu_map[entry].size; entry++) {
+ unsigned long addr;
+
+ for(addr = srmmu_map[entry].vbase;
+ addr < (srmmu_map[entry].vbase + srmmu_map[entry].size);
+ addr += (1 << 24))
+ srmmu_v2p_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+ for(addr = srmmu_map[entry].pbase;
+ addr < (srmmu_map[entry].pbase + srmmu_map[entry].size);
+ addr += (1 << 24))
+ srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+ }
+
return; /* SUCCESS! */
}
@@ -2338,7 +2255,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
start += PAGE_SIZE;
}
}
- } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+ } while ((vmaring = vmaring->vm_next_share) != NULL);
if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = srmmu_pgd_offset(vma->vm_mm, address);
@@ -2355,13 +2272,19 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
static void hypersparc_destroy_context(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT && mm->count == 1) {
+ ctxd_t *ctxp;
+
/* HyperSparc is copy-back, any data for this
* process in a modified cache line is stale
* and must be written back to main memory now
* else we eat shit later big time.
*/
flush_cache_mm(mm);
- ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
+
+ ctxp = &srmmu_context_table[mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4))));
+ hypersparc_flush_page_to_ram((unsigned long)ctxp);
+
flush_tlb_mm(mm);
free_context(mm->context);
mm->context = NO_CONTEXT;
@@ -2450,6 +2373,11 @@ static void poke_hypersparc(void)
hyper_flush_whole_icache();
clear = srmmu_get_faddr();
clear = srmmu_get_fstatus();
+
+#ifdef __SMP__
+ /* Avoid unnecessary cross calls. */
+ flush_page_for_dma = local_flush_page_for_dma;
+#endif
}
__initfunc(static void init_hypersparc(void))
@@ -2482,6 +2410,14 @@ __initfunc(static void init_hypersparc(void))
update_mmu_cache = srmmu_vac_update_mmu_cache;
sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir;
poke_srmmu = poke_hypersparc;
+
+ /* High performance page copy/clear. */
+ { extern void (*__copy_1page)(void *, const void *);
+ extern void (*bzero_1page)(void *);
+
+ __copy_1page = hypersparc_copy_1page;
+ bzero_1page = hypersparc_bzero_1page;
+ }
}
static void poke_cypress(void)
@@ -3014,9 +2950,7 @@ __initfunc(void ld_mmu_srmmu(void))
mmu_p2v = srmmu_p2v;
/* Task struct and kernel stack allocating/freeing. */
- alloc_kernel_stack = srmmu_alloc_kernel_stack;
alloc_task_struct = srmmu_alloc_task_struct;
- free_kernel_stack = srmmu_free_kernel_stack;
free_task_struct = srmmu_free_task_struct;
quick_kernel_fault = srmmu_quick_kernel_fault;
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index ebeada4c7..a0ffc10ed 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $
+/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -1093,8 +1093,7 @@ static void sun4c_quick_kernel_fault(unsigned long address)
panic("sun4c kernel fault handler bolixed...");
}
-/*
- * 4 page buckets for task struct and kernel stack allocation.
+/* 2 page buckets for task struct and kernel stack allocation.
*
* TASK_STACK_BEGIN
* bucket[0]
@@ -1105,24 +1104,17 @@ static void sun4c_quick_kernel_fault(unsigned long address)
*
* Each slot looks like:
*
- * page 1 -- task struct
- * page 2 -- unmapped, for stack redzone (maybe use for pgd)
- * page 3/4 -- kernel stack
+ * page 1 -- task struct + beginning of kernel stack
+ * page 2 -- rest of kernel stack
*/
-struct task_bucket {
- struct task_struct task;
- char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
- char kstack[(PAGE_SIZE*3)];
-};
-
-struct task_bucket *sun4c_bucket[NR_TASKS];
+union task_union *sun4c_bucket[NR_TASKS];
static int sun4c_lowbucket_avail;
-#define BUCKET_EMPTY ((struct task_bucket *) 0)
-#define BUCKET_SIZE (PAGE_SIZE << 2)
-#define BUCKET_SHIFT 14 /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_EMPTY ((union task_union *) 0)
+#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_SIZE (1 << BUCKET_SHIFT)
#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
#define BUCKET_PTE(page) \
@@ -1177,10 +1169,10 @@ static inline void garbage_collect(int entry)
{
int start, end;
- /* 16 buckets per segment... */
- entry &= ~15;
+ /* 32 buckets per segment... */
+ entry &= ~31;
start = entry;
- for(end = (start + 16); start < end; start++)
+ for(end = (start + 32); start < end; start++)
if(sun4c_bucket[start] != BUCKET_EMPTY)
return;
@@ -1190,121 +1182,70 @@ static inline void garbage_collect(int entry)
static struct task_struct *sun4c_alloc_task_struct(void)
{
- unsigned long addr, page;
+ unsigned long addr, pages;
int entry;
- page = get_free_page(GFP_KERNEL);
- if(!page)
+ pages = __get_free_pages(GFP_KERNEL, 1, 0);
+ if(!pages)
return (struct task_struct *) 0;
for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++)
if(sun4c_bucket[entry] == BUCKET_EMPTY)
break;
if(entry == NR_TASKS) {
- free_page(page);
+ free_pages(pages, 1);
return (struct task_struct *) 0;
}
if(entry >= sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry + 1;
addr = BUCKET_ADDR(entry);
- sun4c_bucket[entry] = (struct task_bucket *) addr;
+ sun4c_bucket[entry] = (union task_union *) addr;
if(sun4c_get_segmap(addr) == invalid_segment)
get_locked_segment(addr);
- sun4c_put_pte(addr, BUCKET_PTE(page));
+ sun4c_put_pte(addr, BUCKET_PTE(pages));
+ sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
return (struct task_struct *) addr;
}
-static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
-{
- unsigned long saddr = (unsigned long) tsk;
- unsigned long page[2];
-
- if(!saddr)
- return 0;
- page[0] = __get_free_page(GFP_KERNEL);
- if(!page[0])
- return 0;
- page[1] = __get_free_page(GFP_KERNEL);
- if(!page[1]) {
- free_page(page[0]);
- return 0;
- }
-
- saddr += PAGE_SIZE << 1;
- sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
- sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
- return saddr;
-}
-
-static void sun4c_free_kernel_stack_hw(unsigned long stack)
-{
- unsigned long page[2];
-
- page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
- page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
- /* We are deleting a mapping, so the flushes here are mandatory. */
- sun4c_flush_page_hw(stack);
- sun4c_flush_page_hw(stack + PAGE_SIZE);
-
- sun4c_put_pte(stack, 0);
- sun4c_put_pte(stack + PAGE_SIZE, 0);
- free_page(page[0]);
- free_page(page[1]);
-}
-
static void sun4c_free_task_struct_hw(struct task_struct *tsk)
{
unsigned long tsaddr = (unsigned long) tsk;
- unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
int entry = BUCKET_NUM(tsaddr);
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page_hw(tsaddr);
+ sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
sun4c_put_pte(tsaddr, 0);
+ sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
sun4c_bucket[entry] = BUCKET_EMPTY;
if(entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
- free_page(page);
+ free_pages(pages, 1);
garbage_collect(entry);
}
-static void sun4c_free_kernel_stack_sw(unsigned long stack)
-{
- unsigned long page[2];
-
- page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
- page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
- /* We are deleting a mapping, so the flushes here are mandatory. */
- sun4c_flush_page_sw(stack);
- sun4c_flush_page_sw(stack + PAGE_SIZE);
-
- sun4c_put_pte(stack, 0);
- sun4c_put_pte(stack + PAGE_SIZE, 0);
- free_page(page[0]);
- free_page(page[1]);
-}
-
static void sun4c_free_task_struct_sw(struct task_struct *tsk)
{
unsigned long tsaddr = (unsigned long) tsk;
- unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
int entry = BUCKET_NUM(tsaddr);
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page_sw(tsaddr);
+ sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
sun4c_put_pte(tsaddr, 0);
+ sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
sun4c_bucket[entry] = BUCKET_EMPTY;
if(entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
- free_page(page);
+ free_pages(pages, 1);
garbage_collect(entry);
}
@@ -1312,8 +1253,8 @@ __initfunc(static void sun4c_init_buckets(void))
{
int entry;
- if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
- prom_printf("task bucket not 4 pages!\n");
+ if(sizeof(union task_union) != (PAGE_SIZE << 1)) {
+ prom_printf("task union not 2 pages!\n");
prom_halt();
}
for(entry = 0; entry < NR_TASKS; entry++)
@@ -2526,7 +2467,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
start += PAGE_SIZE;
}
}
- } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+ } while ((vmaring = vmaring->vm_next_share) != NULL);
if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
@@ -2645,7 +2586,6 @@ __initfunc(void ld_mmu_sun4c(void))
flush_tlb_mm = sun4c_flush_tlb_mm_hw;
flush_tlb_range = sun4c_flush_tlb_range_hw;
flush_tlb_page = sun4c_flush_tlb_page_hw;
- free_kernel_stack = sun4c_free_kernel_stack_hw;
free_task_struct = sun4c_free_task_struct_hw;
switch_to_context = sun4c_switch_to_context_hw;
destroy_context = sun4c_destroy_context_hw;
@@ -2658,7 +2598,6 @@ __initfunc(void ld_mmu_sun4c(void))
flush_tlb_mm = sun4c_flush_tlb_mm_sw;
flush_tlb_range = sun4c_flush_tlb_range_sw;
flush_tlb_page = sun4c_flush_tlb_page_sw;
- free_kernel_stack = sun4c_free_kernel_stack_sw;
free_task_struct = sun4c_free_task_struct_sw;
switch_to_context = sun4c_switch_to_context_sw;
destroy_context = sun4c_destroy_context_sw;
@@ -2736,7 +2675,6 @@ __initfunc(void ld_mmu_sun4c(void))
mmu_p2v = sun4c_p2v;
/* Task struct and kernel stack allocating/freeing. */
- alloc_kernel_stack = sun4c_alloc_kernel_stack;
alloc_task_struct = sun4c_alloc_task_struct;
quick_kernel_fault = sun4c_quick_kernel_fault;
diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
new file mode 100644
index 000000000..2a598cd7b
--- /dev/null
+++ b/arch/sparc/mm/tsunami.S
@@ -0,0 +1,90 @@
+/* $Id: tsunami.S,v 1.1 1997/05/03 05:09:09 davem Exp $
+ * tsunami.S: High speed MicroSparc-I mmu/cache operations.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2) \
+ mov 0, tmp1; \
+98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \
+ orcc %g0, tmp2, %g0; \
+ add tmp1, 1, tmp1; \
+ bne 98b; \
+ save %sp, -64, %sp; \
+99: subcc tmp1, 1, tmp1; \
+ bne 99b; \
+ restore %g0, %g0, %g0;
+
+ .text
+ .align 4
+
+ .globl tsunami_flush_cache_all, tsunami_flush_cache_mm
+ .globl tsunami_flush_cache_range, tsunami_flush_cache_page
+ .globl tsunami_flush_page_to_ram, tsunami_flush_page_for_dma
+ .globl tsunami_flush_sig_insns, tsunami_flush_chunk
+ .globl tsunami_flush_tlb_all, tsunami_flush_tlb_mm
+ .globl tsunami_flush_tlb_range, tsunami_flush_tlb_page
+
+ /* Sliiick... */
+tsunami_flush_cache_page:
+ ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+tsunami_flush_cache_mm:
+tsunami_flush_cache_range:
+ ld [%o0 + AOFF_mm_context], %g2
+#ifndef __SMP__
+ cmp %g2, -1
+ be tsunami_flush_cache_out
+#endif
+tsunami_flush_cache_all:
+ WINDOW_FLUSH(%g4, %g5)
+tsunami_flush_page_for_dma:
+ sta %g0, [%g0] ASI_M_DC_FLCLEAR
+ sta %g0, [%g0] ASI_M_IC_FLCLEAR
+tsunami_flush_cache_out:
+tsunami_flush_page_to_ram:
+tsunami_flush_chunk:
+ retl
+ nop
+
+tsunami_flush_sig_insns:
+ flush %o1
+ retl
+ flush %o1 + 4
+
+ /* More slick stuff... */
+tsunami_flush_tlb_mm:
+tsunami_flush_tlb_range:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g2
+ cmp %g2, -1
+ be tsunami_flush_tlb_out
+#endif
+tsunami_flush_tlb_all:
+ mov 0x400, %o1
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+tsunami_flush_tlb_out:
+ retl
+ nop
+
+ /* This one can be done in a fine grained manner... */
+tsunami_flush_tlb_page:
+ ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + AOFF_mm_context], %o3
+ andn %o1, (PAGE_SIZE - 1), %o1
+#ifndef __SMP__
+ cmp %o3, -1
+ be tsunami_flush_tlb_page_out
+#endif
+ lda [%g1] ASI_M_MMUREGS, %g5
+ sta %o3, [%g1] ASI_M_MMUREGS
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+tsunami_flush_tlb_page_out:
+ retl
+ sta %g5, [%g1] ASI_M_MMUREGS
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index f61aa4398..19d426ec7 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -1,4 +1,4 @@
-/* $Id: viking.S,v 1.2 1997/04/20 21:21:49 ecd Exp $
+/* $Id: viking.S,v 1.3 1997/05/04 10:02:14 ecd Exp $
* viking.S: High speed Viking cache/mmu operations
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -38,40 +38,26 @@
viking_flush_page:
viking_flush_chunk:
- sethi %hi(C_LABEL(srmmu_map)), %g2
- or %g2, %lo(C_LABEL(srmmu_map)), %g3
- ld [%g3 + 8], %g2
- cmp %g2, 0
- be 3f
+ sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
+ or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
+ srl %o0, 24, %o1
+ sll %o1, 2, %o1
+
+ ld [%g2 + %o1], %g3
+ cmp %g3, 0
+ bne 1f
and %o0, PAGE_MASK, %o0
- ld [%g3], %o1
-1:
- cmp %o1, %o0
- bgu,a 2f
- add %g3, 0xc, %g3
-
- add %o1, %g2, %g2
- cmp %g2, %o0
- bleu,a 2f
- add %g3, 0xc, %g3
+ retl
+ nop
+1:
+ ld [%g3], %o1
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
add %g2, %o0, %g3
- b 4f
- srl %g3, 12, %g1 ! ppage >> 12
-
-2:
- ld [%g3 + 8], %g2
- cmp %g2, 0
- bne,a 1b
- ld [%g3], %o1
-3:
- retl
- nop
+ srl %g3, 12, %g1 ! ppage >> 12
-4:
clr %o1 ! set counter, 0 - 127
sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3
sethi %hi(0x80000000), %o4
@@ -131,40 +117,27 @@ viking_flush_chunk:
viking_mxcc_flush_page:
- sethi %hi(C_LABEL(srmmu_map)), %g2
- or %g2, %lo(C_LABEL(srmmu_map)), %g3
- ld [%g3 + 8], %g2
- cmp %g2, 0
- be 3f
+ sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
+ or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
+ srl %o0, 24, %o1
+ sll %o1, 2, %o1
+
+ ld [%g2 + %o1], %g3
+ cmp %g3, 0
+ bne 1f
and %o0, PAGE_MASK, %o0
- ld [%g3], %o1
-1:
- cmp %o1, %o0
- bgu,a 2f
- add %g3, 0xc, %g3
-
- add %o1, %g2, %g2
- cmp %g2, %o0
- bleu,a 2f
- add %g3, 0xc, %g3
+ retl
+ nop
+1:
+ ld [%g3], %o1
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
+ sethi %hi(PAGE_SIZE), %g4
add %g2, %o0, %g3
- sethi %hi(PAGE_SIZE), %g4
- b 4f
- add %g3, %g4, %g3 ! ppage + PAGE_SIZE
-
-2:
- ld [%g3 + 8], %g2
- cmp %g2, 0
- bne,a 1b
- ld [%g3], %o1
-3:
- retl
- nop
-4:
+ add %g3, %g4, %g3 ! ppage + PAGE_SIZE
+
mov 0x10, %g2 ! set cacheable bit
sethi %hi(MXCC_SRCSTREAM), %o2
or %o2, %lo(MXCC_SRCSTREAM), %o2
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 9551094d0..4c999477b 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $
+/* $Id: console.c,v 1.14 1997/05/14 20:44:58 davem Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
@@ -14,6 +14,9 @@
#include <asm/system.h>
#include <linux/string.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Non blocking get character from console input device, returns -1
* if no input was taken. This can be used for polling.
*/
@@ -38,11 +41,12 @@ prom_nbgetchar(void)
}
break;
case PROM_AP1000:
+ default:
i = -1;
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -81,9 +85,12 @@ prom_nbputchar(char c)
#endif
break;
+ default:
+ i = -1;
+ break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -130,7 +137,7 @@ prom_query_input_device()
save_flags(flags); cli();
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
if(prom_node_has_property(st_p, "keyboard"))
@@ -177,7 +184,7 @@ prom_query_output_device()
save_flags(flags); cli();
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
@@ -208,6 +215,7 @@ prom_query_output_device()
}
break;
case PROM_AP1000:
+ default:
return PROMDEV_I_UNK;
};
return PROMDEV_O_UNK;
diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c
index 841d63a47..cd99ac3d6 100644
--- a/arch/sparc/prom/devmap.c
+++ b/arch/sparc/prom/devmap.c
@@ -1,4 +1,4 @@
-/* $Id: devmap.c,v 1.3 1996/09/19 20:27:19 davem Exp $
+/* $Id: devmap.c,v 1.5 1997/05/14 20:44:59 davem Exp $
* promdevmap.c: Map device/IO areas to virtual addresses.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Just like the routines in palloc.c, these should not be used
* by the kernel at all. Bootloader facility mainly. And again,
* this is only available on V2 proms and above.
@@ -33,7 +36,7 @@ prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes)
ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
num_bytes);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return ret;
@@ -49,7 +52,7 @@ prom_unmapio(char *vaddr, unsigned int num_bytes)
save_flags(flags); cli();
(*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return;
diff --git a/arch/sparc/prom/devops.c b/arch/sparc/prom/devops.c
index 2b33dd2b7..f7feb0815 100644
--- a/arch/sparc/prom/devops.c
+++ b/arch/sparc/prom/devops.c
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $
+/* $Id: devops.c,v 1.10 1997/05/14 20:44:59 davem Exp $
* devops.c: Device operations using the PROM.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Open the device described by the string 'dstr'. Returns the handle
* to that device used for subsequent operations on that device.
* Returns -1 on failure.
@@ -35,7 +38,7 @@ prom_devopen(char *dstr)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -57,10 +60,11 @@ prom_devclose(int dhandle)
(*(romvec->pv_v2devops.v2_dev_close))(dhandle);
break;
case PROM_AP1000:
+ default:
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return 0;
@@ -83,10 +87,11 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
(*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
break;
case PROM_AP1000:
+ default:
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
index d23d93f61..fede033dd 100644
--- a/arch/sparc/prom/misc.c
+++ b/arch/sparc/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $
+/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -13,6 +13,9 @@
#include <asm/oplib.h>
#include <asm/auxio.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Reset and reboot the machine with the command 'bcommand'. */
void
prom_reboot(char *bcommand)
@@ -22,7 +25,7 @@ prom_reboot(char *bcommand)
(*(romvec->pv_reboot))(bcommand);
/* Never get here. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
}
@@ -40,7 +43,7 @@ prom_feval(char *fstring)
else
(*(romvec->pv_fortheval.v2_eval))(fstring);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
}
@@ -72,7 +75,7 @@ prom_cmdline(void)
save_flags(flags); cli();
(*(romvec->pv_abort))();
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
install_linux_ticker();
@@ -97,7 +100,7 @@ again:
(*(romvec->pv_halt))();
/* Never get here. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
goto again; /* PROM is out to get me -DaveM */
diff --git a/arch/sparc/prom/mp.c b/arch/sparc/prom/mp.c
index cf71cca60..8f07f9d40 100644
--- a/arch/sparc/prom/mp.c
+++ b/arch/sparc/prom/mp.c
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $
+/* $Id: mp.c,v 1.9 1997/05/14 20:45:01 davem Exp $
* mp.c: OpenBoot Prom Multiprocessor support routines. Don't call
* these on a UP or else you will halt and catch fire. ;)
*
@@ -12,6 +12,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Start cpu with prom-tree node 'cpunode' using context described
* by 'ctable_reg' in context 'ctx' at program counter 'pc'.
*
@@ -36,7 +39,7 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -65,7 +68,7 @@ prom_stopcpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -94,7 +97,7 @@ prom_idlecpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
@@ -123,7 +126,7 @@ prom_restartcpu(int cpunode)
break;
};
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c
index cb1def0e1..96b543727 100644
--- a/arch/sparc/prom/segment.c
+++ b/arch/sparc/prom/segment.c
@@ -1,4 +1,4 @@
-/* $Id: segment.c,v 1.3 1996/09/19 20:27:28 davem Exp $
+/* $Id: segment.c,v 1.5 1997/05/14 20:45:02 davem Exp $
* segment.c: Prom routine to map segments in other contexts before
* a standalone is completely mapped. This is for sun4 and
* sun4c architectures only.
@@ -12,6 +12,9 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
+
/* Set physical segment 'segment' at virtual address 'vaddr' in
* context 'ctx'.
*/
@@ -22,7 +25,7 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment)
save_flags(flags); cli();
(*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
- "r" (&current_set[smp_processor_id()]) :
+ "r" (&current_set[hard_smp_processor_id()]) :
"memory");
restore_flags(flags);
return;
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c
index e5e2ceb3d..251b2ee6a 100644
--- a/arch/sparc/prom/tree.c
+++ b/arch/sparc/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $
+/* $Id: tree.c,v 1.18 1997/05/14 20:45:03 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -15,10 +15,12 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+/* XXX Let's get rid of this thing if we can... */
+extern struct task_struct *current_set[NR_CPUS];
/* Macro to restore "current" to the g6 register. */
#define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \
- "r" (&current_set[smp_processor_id()]) : \
+ "r" (&current_set[hard_smp_processor_id()]) : \
"memory")
static char promlib_buf[128];
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index bacf9b095..a70f9ebf8 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 1997/04/14 17:04:49 jj Exp $
+# $Id: Makefile,v 1.16 1997/05/04 07:21:08 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -29,7 +29,7 @@ CFLAGS := $(CFLAGS) -pipe \
LINKFLAGS = -T arch/sparc64/vmlinux.lds
-HEAD := arch/sparc64/kernel/head.o
+HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \
arch/sparc64/prom
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 9ecbf90b4..fbc4a5073 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -40,6 +40,7 @@ SUN_FB_CGFOURTEEN=y
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
@@ -132,8 +133,8 @@ CONFIG_SUNLANCE=y
#
# Filesystems
#
-CONFIG_QUOTA=y
-CONFIG_MINIX_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
@@ -141,7 +142,9 @@ CONFIG_EXT2_FS=y
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
+CONFIG_ROOT_NFS=y
+CONFIG_RNFS_BOOTP=y
+# CONFIG_RNFS_RARP is not set
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index d66fa06e7..4a07295e1 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.16 1997/04/17 20:35:37 jj Exp $
+# $Id: Makefile,v 1.20 1997/05/18 08:42:11 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -13,12 +13,12 @@
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
systbls.o traps.o entry.o devices.o auxio.o ioport.o \
- irq.o time.o sys_sparc.o
+ irq.o time.o sys_sparc.o signal.o winfixup.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_SPARC32_COMPAT
@@ -26,12 +26,17 @@ ifdef CONFIG_SPARC32_COMPAT
endif
ifdef CONFIG_BINFMT_ELF32
- O_OBJS += sparcelf32.o
+ O_OBJS += binfmt_elf32.o
endif
head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+#
+# This is just to get the dependencies...
+#
+binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
+
check_asm: dummy
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -E tmp.c -o tmp.i
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
new file mode 100644
index 000000000..05d50fe56
--- /dev/null
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -0,0 +1,34 @@
+/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ */
+
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+#undef start_thread
+#define start_thread start_thread32
+#define init_elf_binfmt init_elf32_binfmt
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
+MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 8eec19260..2cf372ca9 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
@@ -18,30 +18,30 @@
/*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
/*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset
/*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
- /*0x10*/ and %g4, %g2, %g3 ! Mask PMD offset
+ /*0x10*/ and %g4, %g2, %g4 ! Mask PMD offset
/*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
- /*0x18*/ ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 ! Load PMD
+ /*0x18*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD
/*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
/* ICACHE line 2 */
/*0x20*/ srlx %g1, 1, %g1 ! PTE offset
/*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE
/*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable?
- /*0x2c*/ be,pt %xcc, sparc64_dtlb_fault ! Nope...
+ /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! Nope...
/*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is
/*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page
- /*0x38*/ ldxa [%g5] ASI_DMMU, %g1 ! From MMU
- /*0x3c*/ add %g2, 7, %g5 ! Compute mask
+ /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg
+ /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU
/* ICACHE line 3 */
- /*0x40*/ andn %g1, %g5, %g1 ! Mask page
- /*0x44*/ or %g1, 0x10, %g1 ! 2ndary Context
- /*0x48*/ stxa %g0, [%g1] ASI_DMMU_DEMAP ! TLB flush page
- /*0x4c*/ membar #Sync ! Synchronize
- /*0x50*/ stxa %g3, [%g4 + %g1] ASI_PHYS_USE_EC ! Update sw PTE
- /*0x54*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x58*/ retry ! Trap return
- /*0x5c*/ nop
+ /*0x40*/ add %g2, 7, %g5 ! Compute mask
+ /*0x44*/ andn %g4, %g5, %g4 ! Mask page
+ /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context
+ /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x50*/ membar #Sync ! Synchronize
+ /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x5c*/ retry ! Trap return
/* ICACHE line 4 */
/*0x60*/ nop
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 16fe5c8a0..589d1661a 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
+/* $Id: entry.S,v 1.21 1997/05/18 10:04:44 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -24,31 +24,70 @@
.text
.align 4
-/* FIXME: This is still debugging hack */
- .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
-sparc64_dtlb_fault:
+ .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
+ .globl sparc64_itlb_refbit_catch
+
+ /* Note, DMMU SFAR not updated for fast tlb data access miss
+ * traps, so we must use tag access to find the right page.
+ * However for DMMU fast protection traps it is updated so
+ * we use, but we must also clear it _before_ we enable interrupts
+ * and save state because there is a race where we can push a user
+ * window right now in etrap, a protection fault happens (for example
+ * to update the dirty bit) and since we left crap in the sfsr
+ * it will not get updated properly.
+ */
+sparc64_dtlb_prot_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ ldxa [%g0 + TLB_SFSR] %asi, %g4
+ cmp %g2, 1
+ stxa %g0, [%g0 + TLB_SFSR] %asi
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_fault_handler
- nop
+ b,a,pt %xcc, 1f
sparc64_dtlb_refbit_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ cmp %g2, 1
+ clr %g4 ! sfsr not updated for tlb misses
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_refbit_handler
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+1:
+ mov %l5, %o4 ! raw tag access
+ mov %l4, %o5 ! raw sfsr
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1 ! text_fault == 0
+ sllx %o3, PAGE_SHIFT, %o3 ! address
+ and %l4, 0x4, %o2 ! write == sfsr.W
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
sparc64_itlb_refbit_catch:
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_refbit_handler
- nop
+
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+ mov 1, %o1 ! text_fault == 1
+ clr %o2 ! write == 0
+ clr %o4 ! tag access (N/A)
+ clr %o5 ! raw sfsr (N/A)
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
/* Note check out head.h, this code isn't even used for UP,
* for SMP things will be different. In particular the data
@@ -121,6 +160,7 @@ breakpoint_trap:
ba,a,pt %xcc, rtrap
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+ .globl sys_sigsuspend, sys_sigreturn
sys_pipe:
sethi %hi(sparc_pipe), %g1
@@ -147,12 +187,35 @@ sys_sigpause:
ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
+
+sys_sigsuspend:
+ call do_sigsuspend
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
be,pt %icc, ret_sys_call
- clr %o0
+ nop
call syscall_trace
nop
- ba,pt %xcc, ret_sys_call
- clr %o0
+ ba,a,pt %xcc, rtrap
+
+sys_sigreturn:
+ call do_sigreturn
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, ret_sys_call
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
/* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
.globl sys_fork, sys_vfork, sys_clone
@@ -200,7 +263,7 @@ linux_syscall_trace:
.globl ret_from_syscall
ret_from_syscall:
ba,pt %xcc, ret_sys_call
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
/* Linux native and SunOS system calls enter here... */
.align 4
@@ -232,13 +295,18 @@ syscall_is_too_hard:
call %l7
mov %i5, %o5
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
-
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+#if 0
+ /* Debugging... */
+ call syscall_trace_exit
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+#endif
.globl ret_sys_call
ret_sys_call:
ldx [%curptr + AOFF_task_flags], %l6
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
cmp %o0, -ENOIOCTLCMD
sllx %g2, 32, %g2
bgeu,pn %xcc, 1f
@@ -247,34 +315,34 @@ ret_sys_call:
/* System call success, clear Carry condition code. */
andn %g3, %g2, %g3
clr %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
1:
/* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process.
*/
sub %g0, %o0, %o0
or %g3, %g2, %g3
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
mov 1, %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
linux_syscall_trace2:
call syscall_trace
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
/* End of entry.S */
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 7d293a88b..f936b3071 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,34 +1,39 @@
-/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $
+/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <asm/asi.h>
#include <asm/pstate.h>
#include <asm/ptrace.h>
+#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/head.h>
-/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */
+ /* We assume that pstate, when entering this, has AG and
+ * IE bits set, MG and IG clear.
+ *
+ * We also guarentee for caller that AG %g4 and %g5 will have
+ * their values preserved and left in %l4 and %l5 respectively
+ * for him (fault handling needs this).
+ */
.text
.align 32
.globl etrap, etrap_irq
etrap:
- rdpr %pil, %g4
+ rdpr %pil, %g2
etrap_irq:
rdpr %tstate, %g1
- sllx %g4, 20, %g4
- rdpr %tpc, %g2
- or %g1, %g4, %g1
- rdpr %tnpc, %g3
+ sllx %g2, 20, %g2
+ or %g1, %g2, %g1
/* What happens more often? etrap when already in priv or from userland? */
andcc %g1, TSTATE_PRIV, %g0
bne,a,pn %xcc, 1f
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
/* Just when going from userland to privileged mode,
* we have to change this stuff.
@@ -38,41 +43,48 @@ etrap_irq:
* trap level until PRIMARY_CONTEXT is set to zero, else
* we fall out of NUCLEUS too soon and crash hard.
*/
- rdpr %wstate, %g5
- mov PRIMARY_CONTEXT, %g7
- ldxa [%g7] ASI_DMMU, %g4
- mov SECONDARY_CONTEXT, %g6
- stxa %g0, [%g7] ASI_DMMU
- stxa %g4, [%g6] ASI_DMMU
- wrpr %g0, 0x0, %tl
+ mov PRIMARY_CONTEXT, %g1
+ ldxa [%g1] ASI_DMMU, %g2
+ stxa %g0, [%g1] ASI_DMMU
- sll %g5, 3, %g5
- sethi %uhi(KERNBASE), %g4
- or %g4, %ulo(KERNBASE), %g4
- sethi %hi(current_set), %g6
- or %g6, %lo(current_set), %g6
- sllx %g4, 32, %g4
- wrpr %g5, %wstate
- rdpr %canrestore, %g5
- ldx [%g6 + %g4], %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
- wrpr %g0, 0, %canrestore
- wrpr %g5, 0, %otherwin
- ba,pt %xcc, 2f
- ldx [%g6 + AOFF_task_saved_kernel_stack], %g5
+ mov SECONDARY_CONTEXT, %g1
+ stxa %g2, [%g1] ASI_DMMU
+
+ rd %pic, %g1
+ sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ add %g1, %g2, %g2
+ rdpr %tstate, %g1
1:
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
+ rdpr %tpc, %g1
+ rdpr %tnpc, %g3
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC]
+ rd %y, %g1
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y]
+
wrpr %g0, 0x0, %tl
-2:
- rd %y, %g4
- stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE]
- stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC]
- stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC]
- stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y]
rdpr %pstate, %g1
- save %g5, -STACK_BIAS, %sp
+ save %g2, -STACK_BIAS, %sp
+
+ /* Must guarentee that here andcc of TSTATE_PRIV at the top is
+ * still valid in %ccr register. Don't show this trick to your
+ * mom. -DaveM
+ */
+ bne,pn %xcc, 1f
+ rdpr %canrestore, %g3
+ wrpr %g0, 0, %canrestore
+ wrpr %g3, 0, %otherwin
+
+ rdpr %wstate, %g6
+ sll %g6, 3, %g6
+ wrpr %g6, %wstate
+
+1:
mov %g1, %l1
+ mov %g4, %l4
+ mov %g5, %l5
mov %g7, %l2
wrpr %l1, PSTATE_AG, %pstate
stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
@@ -91,24 +103,13 @@ etrap_irq:
stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
- sethi %uhi(KERNBASE), %g4
- or %g4, %ulo(KERNBASE), %g4
- sethi %hi(current_set), %g6
- or %g6, %lo(current_set), %g6
- sllx %g4, 32, %g4
+ srlx %sp, 43, %g4
+ rd %pic, %g6
jmpl %l2 + 0x4, %g0
- ldx [%g6 + %g4], %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
+ sllx %g4, 43, %g4
.globl etraptl1
etraptl1:
- rdpr %tl, %g4
rdpr %tstate, %g1
- sub %g4, 1, %g4
- rdpr %tpc, %g2
- rdpr %tnpc, %g3
- wrpr %g4, 0x0, %tl
ba,pt %xcc, 1b
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
index 0aca22a77..034bda2d0 100644
--- a/arch/sparc64/kernel/hack.S
+++ b/arch/sparc64/kernel/hack.S
@@ -4,8 +4,6 @@
to compile... */
.text
.align 8
- .globl _sigpause_common
-_sigpause_common: retl;nop
.globl breakpoint
breakpoint: retl;nop
.globl do_cee
@@ -36,8 +34,6 @@ do_fpother_tl1: retl;nop
do_iae: retl;nop
.globl do_iae_tl1
do_iae_tl1: retl;nop
- .globl do_ill
-do_ill: retl;nop
.globl do_ill_tl1
do_ill_tl1: retl;nop
.globl do_irq
@@ -48,8 +44,6 @@ do_irq_tl1: retl;nop
do_lddfmna: retl;nop
.globl do_lddfmna_tl1
do_lddfmna_tl1: retl;nop
- .globl do_mna
-do_mna: retl;nop
.globl do_mna_tl1
do_mna_tl1: retl;nop
.globl do_paw
@@ -60,8 +54,6 @@ do_paw_tl1: retl;nop
do_privact: retl;nop
.globl do_privop
do_privop: retl;nop
- .globl do_signal
-do_signal: retl;nop
.globl do_stdfmna
do_stdfmna: retl;nop
.globl do_stdfmna_tl1
@@ -200,15 +192,7 @@ sunos_write: retl;nop
sunos_writev: retl;nop
.globl sys_ptrace
sys_ptrace: retl;nop
- .globl sys_sigreturn
-sys_sigreturn: retl;nop
- .globl sys_sigstack
-sys_sigstack: retl;nop
- .globl sys_sigsuspend
-sys_sigsuspend: retl;nop
.globl syscall_trace
syscall_trace: retl;nop
.globl sys32_ptrace
sys32_ptrace: retl;nop
- .globl do_sigpause
-do_sigpause: retl;nop
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index fdbe87aa3..4babe3eb4 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $
+/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -262,16 +262,22 @@ sun4u_init:
stx %g6, [%g2 + %g4]
stx %g5, [%g3 + %g4]
- sethi %hi(init_task), %g6
- or %g6, %lo(init_task), %g6
+ sethi %hi(init_task_union), %g6
+ or %g6, %lo(init_task_union), %g6
add %g6, %g4, %g6 ! g6 usage is fixed as well
mov %sp, %l6
mov %o4, %l7
- sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
- or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
- add %g5, %g4, %sp
+ /* Setup "Linux Current Register", thanks Sun 8-) */
+ wr %g0, 0x1, %pcr
+ wr %g6, 0x0, %pic
+
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
mov 0, %fp
+
wrpr %g0, 0, %wstate
wrpr %g0, 0x0, %tl
@@ -287,14 +293,20 @@ sun4u_init:
add %l2, 1, %l2
add %l0, %g4, %o0
1:
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
add %l0, %l2, %l0
cmp %l0, %l1
blu,pt %xcc, 1b
add %l0, %g4, %o0
/* Now clear empty_zero_page */
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
mov %g4, %o0
mov %l6, %o1 ! OpenPROM stack
@@ -361,6 +373,9 @@ bootup_kernel_stack:
#include "ttable.S"
+ /* This is just anal retentiveness on my part... */
+ .align 16384
+
.data
.align 8
.globl nwindows, nwindowsm1
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
new file mode 100644
index 000000000..d0fc09346
--- /dev/null
+++ b/arch/sparc64/kernel/init_task.c
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 5ec62a6b6..4e2bbe016 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $
+/* $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -346,7 +346,14 @@ void flush_thread(void)
}
/* Now, this task is no longer a kernel thread. */
- current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+
+ /* exec_mmap() set context to NO_CONTEXT, here is
+ * where we grab a new one.
+ */
+ get_mmu_context(current);
+ }
current->tss.current_ds = USER_DS;
}
@@ -416,6 +423,64 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
return sp;
}
+/* Standard stuff. */
+static inline void shift_window_buffer(int first_win, int last_win,
+ struct thread_struct *tp)
+{
+ int i;
+
+ for(i = first_win; i < last_win; i++) {
+ tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+ memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+ sizeof(struct reg_window));
+ }
+}
+
+void synchronize_user_stack(void)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+
+ flush_user_windows();
+ if(window) {
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(!copy_to_user((char *)sp, rwin, winsize)) {
+ shift_window_buffer(window, tp->w_saved - 1, tp);
+ tp->w_saved--;
+ }
+ } while(window--);
+ }
+}
+
+void fault_in_user_windows(struct pt_regs *regs)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+ if(window) {
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(copy_to_user((char *)sp, rwin, winsize))
+ do_exit(SIGILL);
+ } while(window--);
+ }
+ current->tss.w_saved = 0;
+}
/* Copy a Sparc thread. The fork() return value conventions
* under SunOS are nothing short of bletcherous:
@@ -453,19 +518,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
#endif
/* Calculate offset to stack_frame & pt_regs */
- stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+ stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
if(regs->tstate & TSTATE_PRIV)
stack_offset -= REGWIN_SZ;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
*childregs = *regs;
new_stack = (((struct reg_window *) childregs) - 1);
old_stack = (((struct reg_window *) regs) - 1);
*new_stack = *old_stack;
- p->saved_kernel_stack = ((unsigned long) new_stack);
- p->tss.ksp = p->saved_kernel_stack - STACK_BIAS;
+ p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS;
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
p->tss.kregs = childregs;
@@ -485,7 +549,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.current_ds = USER_DS;
#if 0
- if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf *childstack;
struct sparc_stackf *parentstack;
@@ -494,8 +558,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
* Set some valid stack frames to give to the child.
*/
childstack = (struct sparc_stackf *)sp;
- parentstack = (struct sparc_stackf *)
- current->tss.kregs->u_regs[UREG_FP];
+ parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP];
#if 0
printk("clone: parent stack:\n");
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index dfebd7ad8..1c4c4df04 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
+/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -71,12 +71,11 @@ rtrap:
/* We came here from to_user, ie. we have now AG.
* Also have to push user context back into primary.
*/
- restore
-
mov SECONDARY_CONTEXT, %g6
mov PRIMARY_CONTEXT, %g7
ldxa [%g6] ASI_DMMU, %g4
stxa %g4, [%g7] ASI_DMMU
+ membar #Sync /* XXX flushi would be better -DaveM */
rdpr %wstate, %g1
rdpr %otherwin, %g2
@@ -84,7 +83,6 @@ rtrap:
wrpr %g2, %g0, %canrestore
wrpr %g1, %g0, %wstate
wrpr %g0, %g0, %otherwin
- retry
1:
restore
retry
@@ -101,9 +99,14 @@ to_user:
ldx [%g6 + AOFF_task_blocked], %o0
or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate
andncc %l0, %o0, %g0
- be,pt %xcc, 3b
+ be,pt %xcc, check_user_wins
mov %l5, %o2
mov %l6, %o3
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
call do_signal
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+check_user_wins:
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ brz,pt %o2, 3b
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call fault_in_user_windows
add %o7, 3b-.-4, %o7
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 170e5563e..47d900977 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $
+/* $Id: setup.c,v 1.6 1997/05/04 07:21:04 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -261,6 +261,8 @@ __initfunc(void setup_arch(char **cmdline_p,
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
+ prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line);
+
printk("ARCH: SUN4U\n");
boot_flags_init(*cmdline_p);
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
new file mode 100644
index 000000000..1a595491a
--- /dev/null
+++ b/arch/sparc64/kernel/signal.c
@@ -0,0 +1,438 @@
+/* $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $
+ * arch/sparc64/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+#include <asm/svr4.h>
+#include <asm/pgtable.h>
+#include <asm/fpumacro.h>
+#include <asm/smp_lock.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_o0, int ret_from_syscall);
+
+/* This turned off for production... */
+/* #define DEBUG_SIGNALS 1 */
+
+/*
+ * The new signal frame, intended to be used for Linux applications only
+ * (we have enough in there to work with clone).
+ * All the interesting bits are in the info field.
+ */
+
+struct new_signal_frame {
+ struct sparc_stackf ss;
+ __siginfo_t info;
+ __siginfo_fpu_t * fpu_save;
+ unsigned int insns [2];
+ __siginfo_fpu_t fpu_state;
+};
+
+/* Align macros */
+#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ * This is really tricky on the Sparc, watch out...
+ */
+asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
+{
+ unsigned int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *);
+ _sigpause32_common(set, regs);
+ return;
+ }
+#endif
+ spin_lock_irq(&current->sigmask_lock);
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+
+ /* Condition codes and return value where set here for sigpause,
+ * and so got used by setup_frame, which again causes sigreturn()
+ * to return -EINTR.
+ */
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ /*
+ * Return -EINTR and set condition code here,
+ * so the interrupted system call actually returns
+ * these.
+ */
+ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal(mask, regs, 0, 0))
+ return;
+ }
+}
+
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
+{
+ _sigpause_common(set, regs);
+}
+
+asmlinkage void do_sigsuspend(struct pt_regs *regs)
+{
+ _sigpause_common(regs->u_regs[UREG_I0], regs);
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+ regs->tstate &= ~(TSTATE_PEF);
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+
+ copy_from_user(&current->tss.float_regs[0],
+ &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 64));
+ __get_user(current->tss.fsr, &fpu->si_fsr);
+}
+
+void do_sigreturn(struct pt_regs *regs)
+{
+ struct new_signal_frame *sf;
+ unsigned long tpc, tnpc, tstate;
+ __siginfo_fpu_t *fpu_save;
+ int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void do_sigreturn32(struct pt_regs *);
+ do_sigreturn32(regs);
+ return;
+ }
+#endif
+ synchronize_user_stack ();
+ sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+ /* 1. Make sure we are not getting garbage from the user */
+ if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
+ goto segv;
+ }
+ if (((unsigned long) sf) & 3){
+ goto segv;
+ }
+ get_user(tpc, &sf->info.si_regs.tpc);
+ __get_user(tnpc, &sf->info.si_regs.tnpc);
+ if ((tpc | tnpc) & 3){
+ goto segv;
+ }
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
+ /* 2. Restore the state */
+ __get_user(regs->y, &sf->info.si_regs.y);
+ __get_user(tstate, &sf->info.si_regs.tstate);
+ copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
+
+ /* User can only change condition codes and FPU enabling in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+ regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF));
+
+ __get_user(fpu_save, &sf->fpu_save);
+ if (fpu_save)
+ restore_fpu_state(regs, &sf->fpu_state);
+ __get_user(mask, &sf->info.si_mask);
+ current->blocked = mask & _BLOCKABLE;
+ return;
+segv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void *fp, int fplen)
+{
+ if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x80000000000ULL - fplen)
+ return 1;
+ return 0;
+}
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ fpsave((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+ (sizeof(unsigned int) * 64));
+ __put_user(current->tss.fsr, &fpu->si_fsr);
+ current->used_math = 0;
+}
+
+static inline void
+new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
+ int signo, unsigned long oldmask)
+{
+ struct new_signal_frame *sf;
+ int sigframe_size;
+ unsigned long tmp;
+ int i;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu_t);
+
+ sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size)){
+ lock_kernel ();
+ do_exit(SIGILL);
+ }
+
+ if (current->tss.w_saved != 0){
+ printk ("%s[%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
+ lock_kernel ();
+ do_exit (SIGILL);
+ }
+
+ /* 2. Save the current process state */
+ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
+
+ if (current->used_math) {
+ save_fpu_state(regs, &sf->fpu_state);
+ __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ } else {
+ __put_user(0, &sf->fpu_save);
+ }
+
+ __put_user(oldmask, &sf->info.si_mask);
+ for (i = 0; i < sizeof(struct reg_window)/8; i++) {
+ __get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i));
+ __put_user(tmp, (((u64 *)sf)+i));
+ }
+
+ /* 3. return to kernel instructions */
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */
+
+ /* 4. signal handler back-trampoline and parameters */
+ regs->u_regs[UREG_FP] = (unsigned long) sf;
+ regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+ regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+ /* 5. signal handler */
+ regs->tpc = (unsigned long) sa->sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+ /* Flush instruction space. */
+ __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0])));
+
+}
+
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+ unsigned long oldmask, struct pt_regs *regs)
+{
+ new_setup_frame(sa, regs, signr, oldmask);
+ if(sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ if(!(sa->sa_flags & SA_NOMASK))
+ current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
+ struct sigaction *sa)
+{
+ switch(regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ no_system_call_restart:
+ regs->u_regs[UREG_I0] = EINTR;
+ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ break;
+ case ERESTARTSYS:
+ if(!(sa->sa_flags & SA_RESTART))
+ goto no_system_call_restart;
+ /* fallthrough */
+ case ERESTARTNOINTR:
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ }
+}
+
+/* Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_i0, int restart_syscall)
+{
+ unsigned long signr, mask = ~current->blocked;
+ struct sigaction *sa;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage int do_signal32(unsigned long, struct pt_regs *,
+ unsigned long, int);
+ return do_signal32(oldmask, regs, orig_i0, restart_syscall);
+ }
+#endif
+ while ((signr = current->signal & mask) != 0) {
+ signr = ffz(~signr);
+ clear_bit(signr, &current->signal);
+ sa = current->sig->action + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sig->action + signr - 1;
+ }
+ if(sa->sa_handler == SIG_IGN) {
+ if(signr != SIGCHLD)
+ continue;
+
+ /* sys_wait4() grabs the master kernel lock, so
+ * we need not do so, that sucker should be
+ * threaded and would not be that difficult to
+ * do anyways.
+ */
+ while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ ;
+ continue;
+ }
+ if(sa->sa_handler == SIG_DFL) {
+ if(current->pid == 1)
+ continue;
+ switch(signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+
+ case SIGSTOP:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ if(current->binfmt && current->binfmt->core_dump) {
+ if(current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
+ }
+#ifdef DEBUG_SIGNALS
+ /* Very useful to debug dynamic linker problems */
+ printk ("Sig ILL going...\n");
+ show_regs (regs);
+#endif
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ current->flags |= PF_SIGNALED;
+ do_exit(signr);
+ }
+ }
+ if(restart_syscall)
+ syscall_restart(orig_i0, regs, sa);
+ handle_signal(signr, sa, oldmask, regs);
+ return 1;
+ }
+ if(restart_syscall &&
+ (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+ regs->u_regs[UREG_I0] == ERESTARTSYS ||
+ regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+ /* replay the system call when we are done */
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ }
+ return 0;
+}
+
+asmlinkage int
+sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
+{
+ int ret = -EFAULT;
+
+ lock_kernel();
+ /* First see if old state is wanted. */
+ if(ossptr) {
+ if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+ goto out;
+ }
+
+ /* Now see if we want to update the new state. */
+ if(ssptr) {
+ if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+ goto out;
+ }
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
+}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index e1129dfd6..d8e61511d 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $
+/* $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -30,8 +30,6 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-#define synchronize_user_stack() do { } while (0)
-
asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
@@ -117,17 +115,6 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
}
}
-asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs)
-{
- _sigpause32_common(set, regs);
-}
-
-asmlinkage void do_sigsuspend32(struct pt_regs *regs)
-{
- _sigpause32_common(regs->u_regs[UREG_I0], regs);
-}
-
-
static inline void
restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
{
@@ -248,7 +235,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
{
struct signal_sframe32 *sframep;
struct sigcontext32 *sc;
+#if 0
int window = 0;
+#endif
int old_status = current->tss.sstk_info.cur_status;
unsigned psr;
int i;
@@ -424,7 +413,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_mcontext_t *mc;
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
+#if 0
int window = 0;
+#endif
unsigned psr;
int i;
diff --git a/arch/sparc64/kernel/sparcelf32.c b/arch/sparc64/kernel/sparcelf32.c
deleted file mode 100644
index 855c636e4..000000000
--- a/arch/sparc64/kernel/sparcelf32.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra.
- *
- * This is just binfmt_elf.c with hooks so that the types are those
- * for a 32-bit ELF binaries.
- */
-
-/* This makes it work. */
-#define ELF_ARCH EM_SPARC
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB;
-
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines. Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-#include <linux/elfcore.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-#include <linux/config.h>
-
-#define DLINFO_ITEMS 12
-
-#include <linux/elf.h>
-
-static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs);
-static int load_elf32_library(int fd);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-extern void dump_thread(struct pt_regs *, struct user *);
-
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-
-/*
- * If we don't support core dumping, then supply a NULL so we
- * don't even try.
- */
-#ifdef USE_ELF_CORE_DUMP
-static int elf32_core_dump(long signr, struct pt_regs * regs);
-#else
-#define elf32_core_dump NULL
-#endif
-
-#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-
-static struct linux_binfmt elf32_format = {
-#ifndef MODULE
- NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump
-#else
- NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump
-#endif
-};
-
-static void set_brk(unsigned long start, unsigned long end)
-{
- start = PAGE_ALIGN(start);
- end = PAGE_ALIGN(end);
- if (end <= start)
- return;
- do_mmap(NULL, start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-}
-
-
-/* We need to explicitly zero any fractional pages
- after the data section (i.e. bss). This would
- contain the junk from the file that should not
- be in memory */
-
-
-static void padzero(unsigned long elf_bss)
-{
- unsigned long nbyte;
-
- nbyte = elf_bss & (PAGE_SIZE-1);
- if (nbyte) {
- nbyte = PAGE_SIZE - nbyte;
- clear_user((void *) elf_bss, nbyte);
- }
-}
-
-__u32 *create_elf32_tables(char *p, int argc, int envc,
- struct elfhdr * exec,
- unsigned long load_addr,
- unsigned long interp_load_addr, int ibcs)
-{
- __u32 *argv, *envp;
- __u32 *sp, *csp;
-
- /*
- * Force 16 byte alignment here for generality.
- */
- sp = (__u32 *) (~15UL & (unsigned long) p);
- csp = sp;
- csp -= exec ? DLINFO_ITEMS*2 : 2;
- csp -= envc+1;
- csp -= argc+1;
- if (!(((unsigned long) csp) & 4))
- sp--;
-
- /*
- * Put the ELF interpreter info on the stack
- */
-#define NEW_AUX_ENT(nr, id, val) \
- __put_user ((id), sp+(nr*2)); \
- __put_user ((val), sp+(nr*2+1)); \
-
- sp -= 2;
- NEW_AUX_ENT(0, AT_NULL, 0);
-
- if (exec) {
- sp -= 11*2;
-
- NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
- NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
- NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
- NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
- NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
- NEW_AUX_ENT (5, AT_FLAGS, 0);
- NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry);
- NEW_AUX_ENT (7, AT_UID, (__u32) current->uid);
- NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid);
- NEW_AUX_ENT (9, AT_GID, (__u32) current->gid);
- NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid);
- }
-#undef NEW_AUX_ENT
-
- sp -= envc+1;
- envp = (__u32 *) sp;
- sp -= argc+1;
- argv = (__u32 *) sp;
- if (!ibcs) {
- __put_user(((__u32)(long) envp),--sp);
- __put_user(((__u32)(long) argv),--sp);
- }
-
- __put_user((__u32)argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- __put_user(((__u32)(long)p),argv++);
- p += strlen_user(p);
- }
- __put_user(NULL, argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- __put_user(((__u32)(long)p),envp++);
- p += strlen_user(p);
- }
- __put_user(NULL, envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
- so we keep this separate. Technically the library read function
- is only provided so that we can read a.out libraries that have
- an ELF header */
-
-static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode,
- unsigned long *interp_load_addr)
-{
- struct file * file;
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned long load_addr;
- int load_addr_set = 0;
- int elf_exec_fileno;
- int retval;
- unsigned long last_bss, elf_bss;
- unsigned long error;
- int i;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
-
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
- return ~0UL;
- }
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
- return ~0UL;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
- GFP_KERNEL);
- if (!elf_phdata)
- return ~0UL;
-
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
- {
- kfree(elf_phdata);
- return ~0UL;
- }
-
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
- if (elf_exec_fileno < 0) {
- kfree(elf_phdata);
- return ~0UL;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- unsigned long k;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- } else {
- load_addr = get_unmapped_area(0, eppnt->p_filesz +
- ELF_PAGEOFFSET(eppnt->p_vaddr));
- }
-
- error = do_mmap(file,
- load_addr + ELF_PAGESTART(vaddr),
- eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-
- if (error > -1024UL) {
- /* Real error */
- sys_close(elf_exec_fileno);
- kfree(elf_phdata);
- return ~0UL;
- }
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
-
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
- sys_close(elf_exec_fileno);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss);
- elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss)
- do_mmap(NULL, elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
-
- *interp_load_addr = load_addr;
- return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned long load_aout32_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
-{
- int retval;
- unsigned long elf_entry;
-
- current->mm->brk = interp_ex->a_bss +
- (current->mm->end_data = interp_ex->a_data +
- (current->mm->end_code = interp_ex->a_text));
- elf_entry = interp_ex->a_entry;
-
-
- if (N_MAGIC(*interp_ex) == OMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- interp_ex->a_text+interp_ex->a_data, 0);
- } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
- N_TXTOFF(*interp_ex) ,
- (char *) N_TXTADDR(*interp_ex),
- interp_ex->a_text+interp_ex->a_data, 0);
- } else
- retval = -1;
-
- if (retval >= 0)
- do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
- interp_ex->a_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- if (retval < 0) return ~0UL;
- return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries. There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-
-static inline int
-do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct file * file;
- struct exec interp_ex;
- struct inode *interpreter_inode;
- unsigned long load_addr;
- int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
- unsigned char ibcs2_interpreter;
- int i;
- int old_fs;
- int error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
- unsigned long elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned long elf_entry, interp_load_addr = 0;
- int status;
- unsigned long start_code, end_code, end_data;
- unsigned long elf_stack;
- char passed_fileno[6];
-
- ibcs2_interpreter = 0;
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
- return -ENOEXEC;
- }
-
-
- /* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC &&
- elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine)) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- }
-
- /* Now read in all of the header information */
-
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
- if (elf_phdata == NULL) {
- return -ENOMEM;
- }
-
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum, 1);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_stack = ~0UL;
- elf_interpreter = NULL;
- start_code = ~0UL;
- end_code = 0;
- end_data = 0;
-
- for(i=0;i < elf_ex.e_phnum; i++){
- if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
- if (elf_interpreter == NULL) {
- kfree (elf_phdata);
- sys_close(elf_exec_fileno);
- return -ENOMEM;
- }
-
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,
- elf_interpreter,
- elf_ppnt->p_filesz, 1);
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
- ibcs2_interpreter = 1;
-#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if (retval >= 0) {
- old_fs = get_fs(); /* This could probably be optimized */
- set_fs(get_ds());
- retval = open_namei(elf_interpreter, 0, 0,
- &interpreter_inode, NULL);
- set_fs(old_fs);
- }
-
- if (retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- }
- if (retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return retval;
- }
- }
- elf_ppnt++;
- }
-
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
- if (!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- sys_close(elf_exec_fileno);
- return -ELIBBAD;
- }
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- if (!bprm->sh_bang) {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- kfree(elf_interpreter);
- }
- kfree (elf_phdata);
- sys_close(elf_exec_fileno);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
-
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->start_mmap = ELF_START_MMAP;
- current->mm->mmap = NULL;
- elf_entry = (unsigned long) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- current->mm->rss = 0;
- bprm->p = setup_arg_pages(bprm->p, bprm);
- current->mm->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
-
- old_fs = get_fs();
- set_fs(get_ds());
- for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
- if (elf_ppnt->p_type == PT_LOAD) {
- int elf_prot = 0;
- if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
- if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-
- error = do_mmap(file,
- ELF_PAGESTART(elf_ppnt->p_vaddr),
- (elf_ppnt->p_filesz +
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE |
- MAP_DENYWRITE | MAP_EXECUTABLE),
- (elf_ppnt->p_offset -
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
-#ifdef LOW_ELF_STACK
- if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
- elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
-#endif
-
- if (!load_addr_set) {
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- load_addr_set = 1;
- }
- k = elf_ppnt->p_vaddr;
- if (k < start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-#if 1
- if ((elf_ppnt->p_flags & PF_X) && end_code < k)
-#else
- if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
-#endif
- end_code = k;
- if (end_data < k) end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if (k > elf_brk) elf_brk = k;
- }
- }
- set_fs(old_fs);
-
- if (elf_interpreter) {
- if (interpreter_type & 1)
- elf_entry = load_aout32_interp(&interp_ex,
- interpreter_inode);
- else if (interpreter_type & 2)
- elf_entry = load_elf32_interp(&interp_elf_ex,
- interpreter_inode,
- &interp_load_addr);
-
- iput(interpreter_inode);
- kfree(elf_interpreter);
-
- if (elf_entry == ~0UL) {
- printk("Unable to load interpreter\n");
- kfree(elf_phdata);
- send_sig(SIGSEGV, current, 0);
- return 0;
- }
- }
-
- kfree(elf_phdata);
-
- if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
- current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-
- if (current->exec_domain && current->exec_domain->module)
- __MOD_DEC_USE_COUNT(current->exec_domain->module);
- if (current->binfmt && current->binfmt->module)
- __MOD_DEC_USE_COUNT(current->binfmt->module);
- current->exec_domain = lookup_exec_domain(current->personality);
- current->binfmt = &elf32_format;
- if (current->exec_domain && current->exec_domain->module)
- __MOD_INC_USE_COUNT(current->exec_domain->module);
- if (current->binfmt && current->binfmt->module)
- __MOD_INC_USE_COUNT(current->binfmt->module);
-
-#ifndef VM_STACK_FLAGS
- current->executable = bprm->inode;
- bprm->inode->i_count++;
-#endif
-#ifdef LOW_ELF_STACK
- current->start_stack = bprm->p = elf_stack - 4;
-#endif
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
- current->flags &= ~PF_FORKNOEXEC;
- bprm->p = (unsigned long)
- create_elf32_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
- (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
- if (interpreter_type == INTERPRETER_AOUT)
- current->mm->arg_start += strlen(passed_fileno) + 1;
- current->mm->start_brk = current->mm->brk = elf_brk;
- current->mm->end_code = end_code;
- current->mm->start_code = start_code;
- current->mm->end_data = end_data;
- current->mm->start_stack = bprm->p;
-
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss);
-
-#if 0
- printk("(start_brk) %x\n" , current->mm->start_brk);
- printk("(end_code) %x\n" , current->mm->end_code);
- printk("(start_code) %x\n" , current->mm->start_code);
- printk("(end_data) %x\n" , current->mm->end_data);
- printk("(start_stack) %x\n" , current->mm->start_stack);
- printk("(brk) %x\n" , current->mm->brk);
-#endif
-
- if ( current->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
- }
-
-#ifdef ELF_PLAT_INIT
- /*
- * The ABI may specify that certain registers be set up in special
- * ways (on i386 %edx is the address of a DT_FINI function, for
- * example. This macro performs whatever initialization to
- * the regs structure is required.
- */
- ELF_PLAT_INIT(regs);
-#endif
-
-
- start_thread32(regs, elf_entry, bprm->p);
- if (current->flags & PF_PTRACED)
- send_sig(SIGTRAP, current, 0);
- return 0;
-}
-
-static int
-load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- int retval;
-
- MOD_INC_USE_COUNT;
- retval = do_load_elf32_binary(bprm, regs);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-/* This is really simpleminded and specialized - we are loading an
- a.out library that is given an ELF header. */
-
-static inline int
-do_load_elf32_library(int fd){
- struct file * file;
- struct elfhdr elf_ex;
- struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
- unsigned long len;
- int elf_bss;
- int retval;
- unsigned long bss;
- int error;
- int i,j, k;
-
- len = 0;
- file = current->files->fd[fd];
- inode = file->f_inode;
- elf_bss = 0;
-
- if (!file || !file->f_op)
- return -EACCES;
-
- /* seek to the beginning of the file */
- if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
- return -ENOEXEC;
- } else
- file->f_pos = 0;
-
- set_fs(KERNEL_DS);
- error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
- set_fs(USER_DS);
- if (error != sizeof(elf_ex))
- return -ENOEXEC;
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
- /* First of all, some simple consistency checks */
- if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(elf_ex.e_machine) ||
- (!inode->i_op || !inode->i_op->default_file_ops->mmap))
- return -ENOEXEC;
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
- return -ENOEXEC;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
- if (elf_phdata == NULL)
- return -ENOMEM;
-
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-
- j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-
- if (j != 1) {
- kfree(elf_phdata);
- return -ENOEXEC;
- }
-
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
- /* Now use mmap to map the library into memory. */
- error = do_mmap(file,
- ELF_PAGESTART(elf_phdata->p_vaddr),
- (elf_phdata->p_filesz +
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
- (elf_phdata->p_offset -
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
-
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
- kfree(elf_phdata);
- return error;
- }
-
- padzero(elf_bss);
-
- len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- if (bss > len)
- do_mmap(NULL, len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
- return 0;
-}
-
-static int load_elf32_library(int fd)
-{
- int retval;
-
- MOD_INC_USE_COUNT;
- retval = do_load_elf32_library(fd);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-/*
- * Note that some platforms still use traditional core dumps and not
- * the ELF core dump. Each platform can select it as appropriate.
- */
-#ifdef USE_ELF_CORE_DUMP
-
-/*
- * ELF core dumper
- *
- * Modelled on fs/exec.c:aout_core_dump()
- * Jeremy Fitzhardinge <jeremy@sw.oz.au>
- */
-/*
- * These are the only things you should do on a core-file: use only these
- * functions to write out all the necessary info.
- */
-static int dump_write(struct file *file, const void *addr, int nr)
-{
- return file->f_op->write(file->f_inode, file, addr, nr) == nr;
-}
-
-static int dump_seek(struct file *file, off_t off)
-{
- if (file->f_op->llseek) {
- if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
- return 0;
- } else
- file->f_pos = off;
- return 1;
-}
-
-/*
- * Decide whether a segment is worth dumping; default is yes to be
- * sure (missing info is worse than too much; etc).
- * Personally I'd include everything, and use the coredump limit...
- *
- * I think we should skip something. But I am not sure how. H.J.
- */
-static inline int maydump(struct vm_area_struct *vma)
-{
- if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
- return 0;
-#if 1
- if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
- return 1;
- if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
- return 0;
-#endif
- return 1;
-}
-
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
-
-/* An ELF note in memory */
-struct memelfnote
-{
- const char *name;
- int type;
- unsigned int datasz;
- void *data;
-};
-
-static int notesize(struct memelfnote *en)
-{
- int sz;
-
- sz = sizeof(struct elf_note);
- sz += roundup(strlen(en->name), 4);
- sz += roundup(en->datasz, 4);
-
- return sz;
-}
-
-/* #define DEBUG */
-
-#define DUMP_WRITE(addr, nr) \
- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off) \
- do { if (!dump_seek(file, (off))) return 0; } while(0)
-
-static int writenote(struct memelfnote *men, struct file *file)
-{
- struct elf_note en;
-
- en.n_namesz = strlen(men->name);
- en.n_descsz = men->datasz;
- en.n_type = men->type;
-
- DUMP_WRITE(&en, sizeof(en));
- DUMP_WRITE(men->name, en.n_namesz);
- /* XXX - cast from long long to long to avoid need for libgcc.a */
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
- DUMP_WRITE(men->data, men->datasz);
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
-
- return 1;
-}
-#undef DUMP_WRITE
-#undef DUMP_SEEK
-
-#define DUMP_WRITE(addr, nr) \
- if (!dump_write(&file, (addr), (nr))) \
- goto close_coredump;
-#define DUMP_SEEK(off) \
- if (!dump_seek(&file, (off))) \
- goto close_coredump;
-/*
- * Actual dumper
- *
- * This is a two-pass process; first we find the offsets of the bits,
- * and then they are actually written out. If we run out of core limit
- * we just truncate.
- */
-static int elf32_core_dump(long signr, struct pt_regs * regs)
-{
- int has_dumped = 0;
- struct file file;
- struct inode *inode;
- unsigned short fs;
- char corefile[6+sizeof(current->comm)];
- int segs;
- int i;
- size_t size;
- struct vm_area_struct *vma;
- struct elfhdr elf;
- off_t offset = 0, dataoff;
- int limit = current->rlim[RLIMIT_CORE].rlim_cur;
- int numnote = 4;
- struct memelfnote notes[4];
- struct elf_prstatus prstatus; /* NT_PRSTATUS */
- elf_fpregset_t fpu; /* NT_PRFPREG */
- struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
-
- if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
- return 0;
- current->dumpable = 0;
-
-#ifndef CONFIG_BINFMT_ELF32
- MOD_INC_USE_COUNT;
-#endif
-
- /* Count what's needed to dump, up to the limit of coredump size */
- segs = 0;
- size = 0;
- for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
- if (maydump(vma))
- {
- int sz = vma->vm_end-vma->vm_start;
-
- if (size+sz >= limit)
- break;
- else
- size += sz;
- }
-
- segs++;
- }
-#ifdef DEBUG
- printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
-
- /* Set up header */
- memcpy(elf.e_ident, ELFMAG, SELFMAG);
- elf.e_ident[EI_CLASS] = ELF_CLASS;
- elf.e_ident[EI_DATA] = ELF_DATA;
- elf.e_ident[EI_VERSION] = EV_CURRENT;
- memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-
- elf.e_type = ET_CORE;
- elf.e_machine = ELF_ARCH;
- elf.e_version = EV_CURRENT;
- elf.e_entry = 0;
- elf.e_phoff = sizeof(elf);
- elf.e_shoff = 0;
- elf.e_flags = 0;
- elf.e_ehsize = sizeof(elf);
- elf.e_phentsize = sizeof(struct elf_phdr);
- elf.e_phnum = segs+1; /* Include notes */
- elf.e_shentsize = 0;
- elf.e_shnum = 0;
- elf.e_shstrndx = 0;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
- if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
- inode = NULL;
- goto end_coredump;
- }
- if (!S_ISREG(inode->i_mode))
- goto end_coredump;
- if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_coredump;
- if (!file.f_op->write)
- goto close_coredump;
- has_dumped = 1;
- current->flags |= PF_DUMPCORE;
-
- DUMP_WRITE(&elf, sizeof(elf));
- offset += sizeof(elf); /* Elf header */
- offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
-
- /*
- * Set up the notes in similar form to SVR4 core dumps made
- * with info from their /proc.
- */
- memset(&psinfo, 0, sizeof(psinfo));
- memset(&prstatus, 0, sizeof(prstatus));
-
- notes[0].name = "CORE";
- notes[0].type = NT_PRSTATUS;
- notes[0].datasz = sizeof(prstatus);
- notes[0].data = &prstatus;
- prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- prstatus.pr_sigpend = current->signal;
- prstatus.pr_sighold = current->blocked;
- psinfo.pr_pid = prstatus.pr_pid = current->pid;
- psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
- psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
- psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
-
- /*
- * This transfers the registers from regs into the standard
- * coredump arrangement, whatever that is.
- */
-#ifdef ELF_CORE_COPY_REGS
- ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
-#else
- if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
- {
- printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
- sizeof(elf_gregset_t), sizeof(struct pt_regs));
- }
- else
- *(struct pt_regs *)&prstatus.pr_reg = *regs;
-#endif
-
- notes[1].name = "CORE";
- notes[1].type = NT_PRPSINFO;
- notes[1].datasz = sizeof(psinfo);
- notes[1].data = &psinfo;
- psinfo.pr_state = current->state;
- psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
- psinfo.pr_zomb = psinfo.pr_sname == 'Z';
- psinfo.pr_nice = current->priority-15;
- psinfo.pr_flag = current->flags;
- psinfo.pr_uid = current->uid;
- psinfo.pr_gid = current->gid;
- {
- int i, len;
-
- set_fs(fs);
-
- len = current->mm->arg_end - current->mm->arg_start;
- len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
- copy_from_user(&psinfo.pr_psargs,
- (const char *)current->mm->arg_start, len);
- for(i = 0; i < len; i++)
- if (psinfo.pr_psargs[i] == 0)
- psinfo.pr_psargs[i] = ' ';
- psinfo.pr_psargs[len] = 0;
-
- set_fs(KERNEL_DS);
- }
- strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
-
- notes[2].name = "CORE";
- notes[2].type = NT_TASKSTRUCT;
- notes[2].datasz = sizeof(*current);
- notes[2].data = current;
-
- /* Try to dump the fpu. */
- prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
- if (!prstatus.pr_fpvalid)
- {
- numnote--;
- }
- else
- {
- notes[3].name = "CORE";
- notes[3].type = NT_PRFPREG;
- notes[3].datasz = sizeof(fpu);
- notes[3].data = &fpu;
- }
-
- /* Write notes phdr entry */
- {
- struct elf_phdr phdr;
- int sz = 0;
-
- for(i = 0; i < numnote; i++)
- sz += notesize(&notes[i]);
-
- phdr.p_type = PT_NOTE;
- phdr.p_offset = offset;
- phdr.p_vaddr = 0;
- phdr.p_paddr = 0;
- phdr.p_filesz = sz;
- phdr.p_memsz = 0;
- phdr.p_flags = 0;
- phdr.p_align = 0;
-
- offset += phdr.p_filesz;
- DUMP_WRITE(&phdr, sizeof(phdr));
- }
-
- /* Page-align dumped data */
- dataoff = offset = roundup(offset, PAGE_SIZE);
-
- /* Write program headers for segments dump */
- for(vma = current->mm->mmap, i = 0;
- i < segs && vma != NULL; vma = vma->vm_next) {
- struct elf_phdr phdr;
- size_t sz;
-
- i++;
-
- sz = vma->vm_end - vma->vm_start;
-
- phdr.p_type = PT_LOAD;
- phdr.p_offset = offset;
- phdr.p_vaddr = vma->vm_start;
- phdr.p_paddr = 0;
- phdr.p_filesz = maydump(vma) ? sz : 0;
- phdr.p_memsz = sz;
- offset += phdr.p_filesz;
- phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
- if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
- if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
- phdr.p_align = PAGE_SIZE;
-
- DUMP_WRITE(&phdr, sizeof(phdr));
- }
-
- for(i = 0; i < numnote; i++)
- if (!writenote(&notes[i], &file))
- goto close_coredump;
-
- set_fs(fs);
-
- DUMP_SEEK(dataoff);
-
- for(i = 0, vma = current->mm->mmap;
- i < segs && vma != NULL;
- vma = vma->vm_next) {
- unsigned long addr = vma->vm_start;
- unsigned long len = vma->vm_end - vma->vm_start;
-
- i++;
- if (!maydump(vma))
- continue;
-#ifdef DEBUG
- printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
- DUMP_WRITE((void *)addr, len);
- }
-
- if ((off_t) file.f_pos != offset) {
- /* Sanity check */
- printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
- (off_t) file.f_pos, offset);
- }
-
- close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
-
- end_coredump:
- set_fs(fs);
- iput(inode);
-#ifndef CONFIG_BINFMT_ELF32
- MOD_DEC_USE_COUNT;
-#endif
- return has_dumped;
-}
-#endif /* USE_ELF_CORE_DUMP */
-
-__initfunc(int init_elf32_binfmt(void))
-{
- return register_binfmt(&elf32_format);
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
- /* Install the COFF, ELF and XOUT loaders.
- * N.B. We *rely* on the table being the right size with the
- * right number of free slots...
- */
- return init_elf32_binfmt();
-}
-
-
-void cleanup_module( void)
-{
- /* Remove the COFF and ELF loaders. */
- unregister_binfmt(&elf32_format);
-}
-#endif
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index e9911daed..147b60c34 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $
+/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -27,15 +27,19 @@
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/ncp_fs.h>
+#include <linux/quota.h>
#include <asm/types.h>
#include <asm/poll.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings */
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to
+ * type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings.
+ */
#define A(x) ((unsigned long)x)
extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
@@ -138,6 +142,10 @@ extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
extern asmlinkage int sys_socketcall(int call, unsigned long *args);
extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
+extern asmlinkage int sys_listen(int fd, int backlog);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]);
+extern asmlinkage int sys_shutdown(int fd, int how);
asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
{
@@ -157,6 +165,17 @@ struct ipc_perm32
unsigned short seq;
};
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t32 sem_otime; /* last semop time */
+ __kernel_time_t32 sem_ctime; /* last change time */
+ u32 sem_base; /* ptr to first semaphore in array */
+ u32 sem_pending; /* pending operations to be processed */
+ u32 sem_pending_last; /* last pending operation */
+ u32 undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
struct msqid_ds32
{
struct ipc_perm32 msg_perm;
@@ -212,15 +231,62 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = sys_semget (first, second, third);
goto out;
case SEMCTL: {
- /* XXX union semun32 to union semun64 and back conversion */
union semun fourth;
+ void *pad;
+ unsigned long old_fs;
+ struct semid_ds s;
+
err = -EINVAL;
if (!ptr)
goto out;
err = -EFAULT;
- if(get_user(fourth.__pad, (void **)A(ptr)))
+ if(get_user(pad, (void **)A(ptr)))
goto out;
+ fourth.__pad = pad;
+ switch (third) {
+ case IPC_INFO:
+ case SEM_INFO:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ case SETALL:
+ case IPC_RMID:
+ err = sys_semctl (first, second, third, fourth);
+ goto out;
+ case IPC_SET:
+ if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) {
+ err = -EFAULT;
+ goto out;
+ }
+ /* Fall through */
+ case SEM_STAT:
+ case IPC_STAT:
+ fourth.__pad = &s;
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ switch (third) {
+ case SEM_STAT:
+ case IPC_STAT:
+ if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) ||
+ __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) ||
+ __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) ||
+ __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) ||
+ __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) ||
+ __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) ||
+ __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) ||
+ __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems)))
+ err = -EFAULT;
+ }
goto out;
}
default:
@@ -534,10 +600,50 @@ asmlinkage int sys32_rename(u32 oldname, u32 newname)
return sys_rename((const char *)A(oldname), (const char *)A(newname));
}
-/* XXX: Play with the addr, it will be ugly :(( */
+struct dqblk32 {
+ __u32 dqb_bhardlimit;
+ __u32 dqb_bsoftlimit;
+ __u32 dqb_curblocks;
+ __u32 dqb_ihardlimit;
+ __u32 dqb_isoftlimit;
+ __u32 dqb_curinodes;
+ __kernel_time_t32 dqb_btime;
+ __kernel_time_t32 dqb_itime;
+};
+
asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
{
- return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ int cmds = cmd >> SUBCMDSHIFT;
+ int err;
+ struct dqblk d;
+ unsigned long old_fs;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ break;
+ case Q_SETQUOTA:
+ case Q_SETUSE:
+ case Q_SETQLIM:
+ if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32)))
+ return -EFAULT;
+ d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+ d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+ break;
+ default:
+ return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ set_fs (old_fs);
+ if (cmds == Q_GETQUOTA) {
+ __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+ ((struct dqblk32 *)&d)->dqb_itime = i;
+ ((struct dqblk32 *)&d)->dqb_btime = b;
+ if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32)))
+ return -EFAULT;
+ }
+ return err;
}
static int put_statfs (u32 buf, struct statfs *s)
@@ -1599,20 +1705,224 @@ asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32
return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
}
-/* Continue here */
+struct msghdr32 {
+ u32 msg_name;
+ int msg_namelen;
+ u32 msg_iov;
+ __kernel_size_t32 msg_iovlen;
+ u32 msg_control;
+ __kernel_size_t32 msg_controllen;
+ unsigned msg_flags;
+};
+
+struct cmsghdr32 {
+ __kernel_size_t32 cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ unsigned char cmsg_data[0];
+};
+
asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
{
- return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_sendmsg(fd, &m, flags);
+ set_fs (old_fs);
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
{
- return sys_recvmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_recvmsg(fd, &m, flags);
+ set_fs (old_fs);
+ if (ret >= 0) {
+ /* XXX Handle msg_control stuff... */
+ if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) ||
+ __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)))
+ return -EFAULT;
+ }
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_socketcall(int call, u32 args)
{
- return sys_socketcall(call, (unsigned long *)A(args));
+ static unsigned char nargs[18]={0,3,3,3,2,3,3,3,
+ 4,4,4,6,6,2,5,5,3,3};
+ u32 a[6];
+ u32 a0,a1;
+ int err = -EINVAL;
+ int i;
+
+ lock_kernel();
+ if(call<1||call>SYS_RECVMSG)
+ goto out;
+ err = -EFAULT;
+
+ for (i = 0; i < nargs[call]; i++, args += sizeof (u32))
+ if (get_user(a[i], (u32 *)A(args)))
+ goto out;
+
+ a0=a[0];
+ a1=a[1];
+
+ switch(call)
+ {
+ case SYS_SOCKET:
+ err = sys_socket(a0, a1, a[2]);
+ break;
+ case SYS_BIND:
+ err = sys32_bind(a0, a1, a[2]);
+ break;
+ case SYS_CONNECT:
+ err = sys32_connect(a0, a1, a[2]);
+ break;
+ case SYS_LISTEN:
+ err = sys_listen(a0, a1);
+ break;
+ case SYS_ACCEPT:
+ err = sys32_accept(a0, a1, a[2]);
+ break;
+ case SYS_GETSOCKNAME:
+ err = sys32_getsockname(a0, a1, a[2]);
+ break;
+ case SYS_GETPEERNAME:
+ err = sys32_getpeername(a0, a1, a[2]);
+ break;
+ case SYS_SOCKETPAIR:
+ err = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
+ break;
+ case SYS_SEND:
+ err = sys32_send(a0, a1, a[2], a[3]);
+ break;
+ case SYS_SENDTO:
+ err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_RECV:
+ err = sys32_recv(a0, a1, a[2], a[3]);
+ break;
+ case SYS_RECVFROM:
+ err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_SHUTDOWN:
+ err = sys_shutdown(a0,a1);
+ break;
+ case SYS_SETSOCKOPT:
+ err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_GETSOCKOPT:
+ err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_SENDMSG:
+ err = sys32_sendmsg(a0, a1, a[2]);
+ break;
+ case SYS_RECVMSG:
+ err = sys32_recvmsg(a0, a1, a[2]);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+out:
+ unlock_kernel();
+ return err;
}
extern void check_pending(int signum);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 48648c39d..c9774df06 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
+/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $
* arch/sparc/kernel/traps.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
+#include <asm/uaccess.h>
/* #define TRAP_DEBUG */
@@ -42,6 +43,8 @@ void syscall_trace_entry(struct pt_regs *regs)
void syscall_trace_exit(struct pt_regs *regs)
{
+ printk("Syscall return check, reg dump.\n");
+ show_regs(regs);
}
void sparc64_dtlb_fault_handler (void)
@@ -116,25 +119,45 @@ void die_if_kernel(char *str, struct pt_regs *regs)
show_regs(regs);
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ while(1)
+ barrier();
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
}
-void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
- unsigned long tstate)
+void do_illegal_instruction(struct pt_regs *regs)
{
+ unsigned long pc = regs->tpc;
+ unsigned long tstate = regs->tstate;
+
lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
-#ifdef TRAP_DEBUG
- printk("Ill instr. at pc=%016lx instruction is %08x\n",
- regs->tpc, *(unsigned int *)regs->tpc);
+#if 1
+ {
+ unsigned int insn;
+
+ printk("Ill instr. at pc=%016lx ", pc);
+ get_user(insn, ((unsigned int *)pc));
+ printk("insn=[%08x]\n", insn);
+ }
#endif
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
unlock_kernel();
+
+ while(1)
+ barrier();
+}
+
+void do_mna(struct pt_regs *regs)
+{
+ printk("AIEEE: do_mna at %016lx\n", regs->tpc);
+ show_regs(regs);
+ while(1)
+ barrier();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index f22d85014..326382c3f 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
+/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,7 +13,7 @@ tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception)
tl0_resv009: BTRAP(0x9)
tl0_iae: TRAP(do_iae)
tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill: TRAP(do_ill)
+tl0_ill: TRAP(do_illegal_instruction)
tl0_privop: TRAP(do_privop)
tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
@@ -226,27 +226,3 @@ tl1_f4o: FILL_4_OTHER
tl1_f5o: FILL_5_OTHER
tl1_f6o: FILL_6_OTHER
tl1_f7o: FILL_7_OTHER
-
-#if 0
-/* Unless we are going to have software trap insns in the kernel code, we
- * don't need this. For now we just save 8KB.
- */
-
-#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7)
-
-tl1_sunos: BTRAPTL1(0x100)
-tl1_bkpt: BREAKPOINT_TRAP
-tl1_resv102: BTRAPTL1(0x102)
-tl1_flushw: FLUSH_WINDOW_TRAP
-tl1_resv104: BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
-tl1_resv107: BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a)
-tl1_resv10b: BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e)
-tl1_resv10f: BTRAPTL1(0x10f)
-tl1_resv110: BTRAPSTL1(0x110) BTRAPSTL1(0x118)
-tl1_resv120: BTRAPSTL1(0x120) BTRAPSTL1(0x128)
-tl1_resv130: BTRAPSTL1(0x130) BTRAPSTL1(0x138)
-tl1_resv140: BTRAPSTL1(0x140) BTRAPSTL1(0x148)
-tl1_resv150: BTRAPSTL1(0x150) BTRAPSTL1(0x158)
-tl1_resv160: BTRAPSTL1(0x160) BTRAPSTL1(0x168)
-tl1_resv170: BTRAPSTL1(0x170) BTRAPSTL1(0x178)
-#endif
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
new file mode 100644
index 000000000..a8293c453
--- /dev/null
+++ b/arch/sparc64/kernel/winfixup.S
@@ -0,0 +1,101 @@
+/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+ *
+ * winfixup.S: Handle cases where user stack pointer is found to be bogus.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/head.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/asm_offsets.h>
+
+ .text
+ .align 32
+
+ /* Here are the rules, pay attention.
+ *
+ * The kernel is disallowed from touching user space while
+ * the trap level is greater than zero, except for from within
+ * the window spill/fill handlers. This must be followed
+ * so that we can easily detect the case where we tried to
+ * spill/fill with a bogus (or unmapped) user stack pointer.
+ *
+ * These are layed out in a special way for cache reasons,
+ * don't touch...
+ */
+ .globl winfix_trampoline, fill_fixup, spill_fixup
+fill_fixup:
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ mov %l5, %o4
+ mov %l4, %o5
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1
+ sllx %o3, PAGE_SHIFT, %o3
+ and %l4, 0x4, %o2
+
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,a,pt %xcc, rtrap
+ nop
+winfix_trampoline:
+ andn %g5, 0x7f, %g5
+ add %g5, 0x7c, %g5
+ wrpr %g5, %tnpc
+ done
+
+spill_fixup:
+ rd %pic, %g1
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
+ sll %g2, 3, %g5
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
+ add %g1, %g5, %g5
+ andcc %g7, SPARC_FLAG_32BIT, %g0
+ stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ sll %g2, 5, %g5
+
+ bne,pt %xcc, 1f
+ add %g1, %g5, %g5
+ stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+ stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+ stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ b,a,pt %xcc, 2f
+ add %g2, 1, %g2
+1:
+ std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+ std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ add %g2, 1, %g2
+2:
+ stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+ rdpr %tstate, %g1
+ nop
+
+ andcc %g1, TSTATE_PRIV, %g0
+ be,pn %xcc, fill_fixup
+ saved
+ retry
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index b3f06c18d..d0f023d1b 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $
+/* $Id: blockops.S,v 1.6 1997/05/18 04:16:49 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -31,37 +31,8 @@
.text
.align 4
- .globl bzero_2page, bzero_1page
-bzero_2page:
- /* %o0 = buf */
- mov %o0, %o1
- wr %g0, ASI_BLK_P, %asi
- mov 0x10, %g2
-
- membar #Sync|#StoreLoad
-
- fzero %f48
- fzero %f50
- fzero %f52
- fzero %f54
- fzero %f56
- fzero %f58
- fzero %f60
- fzero %f62
-1:
- BLAST_BLOCK(%o0, 0x000)
- BLAST_BLOCK(%o0, 0x100)
- BLAST_BLOCK(%o0, 0x200)
- BLAST_BLOCK(%o0, 0x300)
- subcc %g2, 1, %g2
- bne,pt %icc, 1b
- add %o0, 0x400, %o0
-
- membar #Sync|#LoadStore|#StoreStore
-
- retl
- mov %o1, %o0
-
+#if 0
+ .globl bzero_1page
bzero_1page:
/* %o0 = buf */
mov %o0, %o1
@@ -89,9 +60,36 @@ bzero_1page:
retl
mov %o1, %o0
+#endif
.globl __bfill64
__bfill64:
+#if 1
+ /* %o0 = buf, %o1 = 64-bit pattern */
+#define FILL_BLOCK(buf, offset) \
+ stx %o1, [buf + offset + 0x38]; \
+ stx %o1, [buf + offset + 0x30]; \
+ stx %o1, [buf + offset + 0x28]; \
+ stx %o1, [buf + offset + 0x20]; \
+ stx %o1, [buf + offset + 0x18]; \
+ stx %o1, [buf + offset + 0x10]; \
+ stx %o1, [buf + offset + 0x08]; \
+ stx %o1, [buf + offset + 0x00];
+
+ mov 0x20, %g2
+1:
+ FILL_BLOCK(%o0, 0x00)
+ FILL_BLOCK(%o0, 0x40)
+ FILL_BLOCK(%o0, 0x80)
+ FILL_BLOCK(%o0, 0xc0)
+ subcc %g2, 1, %g2
+ bne,pt %icc, 1b
+ add %o0, 0x100, %o0
+ retl
+ nop
+#undef FILL_BLOCK
+
+#else
/* %o0 = buf */
stx %o1, [%sp + 0x7ff + 128]
wr %g0, ASI_BLK_P, %asi
@@ -116,7 +114,9 @@ __bfill64:
retl
membar #Sync|#LoadStore|#StoreStore
+#endif
+#if 0
.globl __copy_1page
__copy_1page:
/* %o0 = dst, %o1 = src */
@@ -135,4 +135,4 @@ __copy_1page:
retl
membar #Sync|#LoadStore|#StoreStore
-
+#endif
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 8a06003ee..b63f0d6e8 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -44,13 +44,13 @@
csum_partial_end_cruft:
andcc %o1, 8, %g0 ! check how much
be,pn %icc, 1f ! caller asks %o1 & 0x8
- and %o1, 4, %g3 ! nope, check for word remaining
+ and %o1, 4, %g5 ! nope, check for word remaining
ldd [%o0], %g2 ! load two
addcc %g2, %o2, %o2 ! add first word to sum
addccc %g3, %o2, %o2 ! add second word as well
add %o0, 8, %o0 ! advance buf ptr
addc %g0, %o2, %o2 ! add in final carry
-1: brz,pn %g3, 1f ! nope, skip this code
+1: brz,pn %g5, 1f ! nope, skip this code
andcc %o1, 3, %o1 ! check for trailing bytes
ld [%o0], %g2 ! load it
addcc %g2, %o2, %o2 ! add to sum
@@ -98,15 +98,17 @@ csum_partial: /* %o0=buf, %o1=len, %o2=sum */
srl %o2, 16, %g3
addc %g0, %g3, %g2
sll %o2, 16, %o2
+ and %o0, 0x4, %g7
sll %g2, 16, %g3
srl %o2, 16, %o2
or %g3, %o2, %o2
1: brz,pn %g7, csum_partial_fix_aligned
- nop
+ andn %o1, 0x7f, %o3
ld [%o0 + 0x00], %g2
sub %o1, 4, %o1
addcc %g2, %o2, %o2
add %o0, 4, %o0
+ andn %o1, 0x7f, %o3
addc %g0, %o2, %o2
csum_partial_fix_aligned:
brz,pt %o3, 3f ! none to do
@@ -115,9 +117,9 @@ csum_partial_fix_aligned:
CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
- sub %o3, 128, %o3 ! detract from loop iters
addc %g0, %o2, %o2 ! sink in final carry
- brnz,pt %o3, 5b ! more to do
+ subcc %o3, 128, %o3 ! detract from loop iters
+ bne,pt %icc, 5b ! more to do
add %o0, 128, %o0 ! advance buf ptr
3: brz,pn %g1, cpte ! nope
andcc %o1, 0xf, %o3 ! anything left at all?
@@ -125,7 +127,7 @@ csum_partial_fix_aligned:
srl %g1, 1, %o4 ! compute offset
sub %g7, %g1, %g7 ! adjust jmp ptr
sub %g7, %o4, %g7 ! final jmp ptr adjust
- jmp %g7 + (cpte - 8 - 10b) ! enter the table
+ jmp %g7 + (11f-10b) ! enter the table
add %o0, %g1, %o0 ! advance buf ptr
cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
@@ -134,8 +136,8 @@ cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
- addc %g0, %o2, %o2 ! fetch final carry
- andcc %o1, 0xf, %g0 ! anything left at all?
+11: addc %g0, %o2, %o2 ! fetch final carry
+ andcc %o1, 0xf, %o3 ! anything left at all?
cpte: brnz,pn %o3, csum_partial_end_cruft ! yep, handle it
sethi %uhi(KERNBASE), %g4
mov %o2, %o0 ! return computed csum
@@ -322,13 +324,14 @@ __csum_partial_copy_sparc_generic:
andcc %o0, 0x4, %g0
or %g3, %g7, %g7
1: be,pt %icc, 3f
- andn %g1, 0x7f, %g0
+ andn %g1, 0x7f, %g2
EX(ld [%o0 + 0x00], %g4, add %g1, 0,#)
sub %g1, 4, %g1
EX2(st %g4, [%o1 + 0x00],#)
add %o0, 4, %o0
addcc %g4, %g7, %g7
add %o1, 4, %o1
+ andn %g1, 0x7f, %g2
addc %g0, %g7, %g7
cc_dword_aligned:
3: brz,pn %g2, 3f ! nope, less than one loop remains
@@ -365,7 +368,7 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling
addc %g0, %g7, %g7
- andcc %o3, 0xf, %g0 ! check for low bits set
+ andcc %g1, 0xf, %o3 ! check for low bits set
ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band
sethi %uhi(KERNBASE), %g4 ! restore gfp
mov %g7, %o0 ! give em the computed checksum
@@ -555,7 +558,7 @@ __csum_partial_copy_end:
add %i1, %i2, %i1
2:
mov %i1, %o0
- wr %%g0, ASI_S, %%asi
+ wr %g0, ASI_S, %asi
call __bzero_noasi
mov %i3, %o1
1:
diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S
index ba26a1c01..50ec7bb3d 100644
--- a/arch/sparc64/lib/copy_from_user.S
+++ b/arch/sparc64/lib/copy_from_user.S
@@ -15,12 +15,16 @@
#include <asm/ptrace.h>
#include <asm/asi.h>
+#include <asm/head.h>
+
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S
index 47a6bd337..733953743 100644
--- a/arch/sparc64/lib/copy_to_user.S
+++ b/arch/sparc64/lib/copy_to_user.S
@@ -14,13 +14,17 @@
*/
#include <asm/ptrace.h>
+#include <asm/head.h>
#include <asm/asi.h>
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
+
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index 24bea73fd..30beee3ff 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -8,6 +8,8 @@
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <asm/asi.h>
+
#define LO_MAGIC 0x01010101
#define HI_MAGIC 0x80808080
@@ -19,21 +21,21 @@ __strlen_user:
be,pt %icc, 9f
sethi %hi(HI_MAGIC), %o4
10:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 21f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pn %icc, 4f
or %o4, %lo(HI_MAGIC), %o3
11:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 22f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pt %icc, 5f
sethi %hi(LO_MAGIC), %o4
12:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 23f
add %o0, 1, %o0
ba,pt %icc, 13f
@@ -45,7 +47,7 @@ __strlen_user:
5:
or %o4, %lo(LO_MAGIC), %o2
13:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
2:
sub %o5, %o2, %o4
andcc %o4, %o3, %g0
@@ -68,7 +70,7 @@ __strlen_user:
andcc %o5, 0xff, %g0
bne,a,pt %icc, 2b
14:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
add %o4, 1, %o4
1:
retl
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index 05a48eb5a..e0fb0f09b 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -24,14 +24,14 @@ __strncpy_from_user:
sub %g0, %o2, %o3
add %o0, %o2, %o0
10:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
1:
brz,pn %o4, 2f
stb %o4, [%o0 + %o3]
addcc %o3, 1, %o3
bne,pt %xcc, 1b
11:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
retl
mov %o2, %o0
2:
diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c
index 4e7de16fb..0272b09c2 100644
--- a/arch/sparc64/mm/asyncd.c
+++ b/arch/sparc64/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.1 1996/12/26 10:24:24 davem Exp $
+/* $Id: asyncd.c,v 1.2 1997/05/15 21:14:32 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -153,7 +153,7 @@ static int fault_in_page(int taskid,
if(!pte)
goto no_memory;
if(!pte_present(*pte)) {
- do_no_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
goto finish_up;
}
set_pte(pte, pte_mkyoung(*pte));
@@ -165,12 +165,11 @@ static int fault_in_page(int taskid,
flush_tlb_page(vma, address);
goto finish_up;
}
- do_wp_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
/* Fall through for do_wp_page */
finish_up:
stats.success++;
- update_mmu_cache(vma, address, *pte);
return 0;
no_memory:
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 0dd118c8e..dc28ac339 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.4 1997/03/11 17:37:07 jj Exp $
+/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -134,8 +134,11 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0;
}
+/* #define FAULT_TRACER */
+
asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
- unsigned long address)
+ unsigned long address, unsigned long tag,
+ unsigned long sfsr)
{
struct vm_area_struct *vma;
struct task_struct *tsk = current;
@@ -143,7 +146,19 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write
unsigned long fixup;
unsigned long g2;
int from_user = !(regs->tstate & TSTATE_PRIV);
-
+#ifdef FAULT_TRACER
+ static unsigned long last_addr = 0;
+ static int rcnt = 0;
+
+ printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]"
+ "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr);
+ if(address == last_addr && rcnt++ > 5) {
+ printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+ while(1)
+ barrier();
+ }
+ last_addr = address;
+#endif
lock_kernel ();
down(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -168,7 +183,7 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
goto out;
/*
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 57ca5eb92..cf378a266 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $
+/* $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -457,16 +457,18 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
pte_clear(ptep);
}
-#ifdef DEBUG_MMU
void sparc_ultra_dump_itlb(void)
{
int slot;
- prom_printf ("Contents of itlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of itlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
- slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1));
+ slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
+ slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
}
}
@@ -474,14 +476,16 @@ void sparc_ultra_dump_dtlb(void)
{
int slot;
- prom_printf ("Contents of dtlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of dtlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
- slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1));
+ slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
+ slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
}
}
-#endif
/* paging_init() sets up the page tables */
@@ -643,7 +647,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
high_memory = (void *) end_mem;
start_mem = PAGE_ALIGN(start_mem);
- num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT;
+ num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
addr = PAGE_OFFSET;
while(addr < start_mem) {
@@ -694,6 +698,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
min_free_pages = 16;
free_pages_low = min_free_pages + (min_free_pages >> 1);
free_pages_high = min_free_pages + min_free_pages;
+
+#if 0
+ printk("Testing fault handling...\n");
+ *(char *)0x00000deadbef0000UL = 0;
+#endif
}
void free_initmem (void)
@@ -702,9 +711,14 @@ void free_initmem (void)
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
+ unsigned long page = addr;
+
+ if(page < ((unsigned long)__va(phys_base)))
+ page += phys_base;
+
+ mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(page)].count, 1);
+ free_page(page);
}
}