summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
commit545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch)
treee9ce4bc598d06374bda906f18365984bf22a526a /arch
parent4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff)
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/config.in4
-rw-r--r--arch/alpha/defconfig11
-rw-r--r--arch/alpha/kernel/bios32.c1
-rw-r--r--arch/alpha/kernel/entry.S2
-rw-r--r--arch/alpha/kernel/traps.c72
-rw-r--r--arch/i386/config.in6
-rw-r--r--arch/i386/defconfig6
-rw-r--r--arch/i386/kernel/bios32.c848
-rw-r--r--arch/i386/kernel/entry.S20
-rw-r--r--arch/i386/kernel/head.S3
-rw-r--r--arch/i386/kernel/i386_ksyms.c2
-rw-r--r--arch/i386/kernel/irq.c23
-rw-r--r--arch/i386/kernel/smp.c23
-rw-r--r--arch/i386/kernel/sys_i386.c43
-rw-r--r--arch/i386/kernel/traps.c6
-rw-r--r--arch/i386/lib/checksum.c18
-rw-r--r--arch/i386/mm/fault.c9
-rw-r--r--arch/i386/mm/init.c64
-rw-r--r--arch/m68k/config.in4
-rw-r--r--arch/m68k/kernel/Makefile2
-rw-r--r--arch/m68k/kernel/process.c2
-rw-r--r--arch/m68k/kernel/ptrace.c2
-rw-r--r--arch/m68k/kernel/signal.c4
-rw-r--r--arch/mips/Makefile10
-rw-r--r--arch/mips/config.in35
-rw-r--r--arch/mips/dec/decstation.S8
-rw-r--r--arch/mips/dec/int-handler.S8
-rw-r--r--arch/mips/defconfig10
-rw-r--r--arch/mips/kernel/Makefile4
-rw-r--r--arch/mips/kernel/entry.S17
-rw-r--r--arch/mips/kernel/fpe.c55
-rw-r--r--arch/mips/kernel/irq.c34
-rw-r--r--arch/mips/kernel/mips_ksyms.c18
-rw-r--r--arch/mips/kernel/pci.c26
-rw-r--r--arch/mips/kernel/ptrace.c26
-rw-r--r--arch/mips/kernel/r4k_misc.S35
-rw-r--r--arch/mips/kernel/setup.c12
-rw-r--r--arch/mips/kernel/signal.c14
-rw-r--r--arch/mips/kernel/syscall.c38
-rw-r--r--arch/mips/kernel/syscalls.h22
-rw-r--r--arch/mips/kernel/traps.c28
-rw-r--r--arch/mips/lib/copy_user.S65
-rw-r--r--arch/mips/mm/loadmmu.c5
-rw-r--r--arch/mips/mm/r4xx0.c72
-rw-r--r--arch/mips/sgi/kernel/indy_int.c38
-rw-r--r--arch/mips/sgi/kernel/indy_timer.c13
-rw-r--r--arch/ppc/Makefile100
-rw-r--r--arch/ppc/boot/Makefile77
-rw-r--r--arch/ppc/boot/find_name.c47
-rw-r--r--arch/ppc/boot/head.S77
-rw-r--r--arch/ppc/boot/kbd.c166
-rw-r--r--arch/ppc/boot/misc.c247
-rw-r--r--arch/ppc/boot/mkprep.c32
-rw-r--r--arch/ppc/coffboot/.cvsignore7
-rw-r--r--arch/ppc/coffboot/Makefile50
-rw-r--r--arch/ppc/coffboot/crt0.S24
-rw-r--r--arch/ppc/coffboot/elfextract.c98
-rw-r--r--arch/ppc/coffboot/hack-coff.c79
-rw-r--r--arch/ppc/coffboot/ld.script68
-rw-r--r--arch/ppc/coffboot/main.c185
-rw-r--r--arch/ppc/coffboot/misc.S50
-rw-r--r--arch/ppc/coffboot/nonstdio.h18
-rw-r--r--arch/ppc/coffboot/rs6000.h243
-rw-r--r--arch/ppc/coffboot/start.c280
-rw-r--r--arch/ppc/coffboot/string.S206
-rw-r--r--arch/ppc/coffboot/zlib.c2143
-rw-r--r--arch/ppc/coffboot/zlib.h432
-rw-r--r--arch/ppc/config.in59
-rw-r--r--arch/ppc/defconfig250
-rw-r--r--arch/ppc/ignore65
-rw-r--r--arch/ppc/kernel/Makefile62
-rw-r--r--arch/ppc/kernel/align.c290
-rw-r--r--arch/ppc/kernel/bitops.c201
-rw-r--r--arch/ppc/kernel/checks.c57
-rw-r--r--arch/ppc/kernel/chrp_pci.c156
-rw-r--r--arch/ppc/kernel/chrp_setup.c180
-rw-r--r--arch/ppc/kernel/chrp_time.c132
-rw-r--r--arch/ppc/kernel/head.S302
-rw-r--r--arch/ppc/kernel/idle.c279
-rw-r--r--arch/ppc/kernel/irq.c630
-rw-r--r--arch/ppc/kernel/misc.S11
-rw-r--r--arch/ppc/kernel/mk_defs.c43
-rw-r--r--arch/ppc/kernel/openpic.c546
-rw-r--r--arch/ppc/kernel/pci-bridge.c428
-rw-r--r--arch/ppc/kernel/pci.c754
-rw-r--r--arch/ppc/kernel/pmac_pci.c423
-rw-r--r--arch/ppc/kernel/pmac_setup.c271
-rw-r--r--arch/ppc/kernel/pmac_support.c69
-rw-r--r--arch/ppc/kernel/pmac_time.c87
-rw-r--r--arch/ppc/kernel/ppc_asm.tmpl4
-rw-r--r--arch/ppc/kernel/ppc_defs.head3
-rw-r--r--arch/ppc/kernel/ppc_htab.c221
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c140
-rw-r--r--arch/ppc/kernel/prep_pci.c436
-rw-r--r--arch/ppc/kernel/prep_setup.c294
-rw-r--r--arch/ppc/kernel/prep_time.c239
-rw-r--r--arch/ppc/kernel/process.c430
-rw-r--r--arch/ppc/kernel/prom.c524
-rw-r--r--arch/ppc/kernel/ptrace.c17
-rw-r--r--arch/ppc/kernel/residual.c144
-rw-r--r--arch/ppc/kernel/setup.c268
-rw-r--r--arch/ppc/kernel/signal.c138
-rw-r--r--arch/ppc/kernel/syscalls.c247
-rw-r--r--arch/ppc/kernel/time.c268
-rw-r--r--arch/ppc/kernel/time.h74
-rw-r--r--arch/ppc/kernel/traps.c109
-rw-r--r--arch/ppc/lib/Makefile43
-rw-r--r--arch/ppc/lib/checksum.S192
-rw-r--r--arch/ppc/lib/strcase.c12
-rw-r--r--arch/ppc/lib/string.S345
-rw-r--r--arch/ppc/mkdiff8
-rw-r--r--arch/ppc/mkdist13
-rw-r--r--arch/ppc/mktar9
-rw-r--r--arch/ppc/mm/Makefile27
-rw-r--r--arch/ppc/mm/extable.c65
-rw-r--r--arch/ppc/mm/fault.c121
-rw-r--r--arch/ppc/mm/init.c580
-rw-r--r--arch/ppc/pmac_defconfig274
-rw-r--r--arch/ppc/prep_defconfig250
-rw-r--r--arch/ppc/vmlinux.lds85
-rw-r--r--arch/sparc/ap1000/aplib.c3
-rw-r--r--arch/sparc/ap1000/mpp.c2
-rw-r--r--arch/sparc/ap1000/msc.c2
-rw-r--r--arch/sparc/ap1000/tnet.c2
-rw-r--r--arch/sparc/config.in10
-rw-r--r--arch/sparc/defconfig5
-rw-r--r--arch/sparc/kernel/devices.c27
-rw-r--r--arch/sparc/kernel/head.S20
-rw-r--r--arch/sparc/kernel/process.c7
-rw-r--r--arch/sparc/kernel/ptrace.c2
-rw-r--r--arch/sparc/kernel/rtrap.S8
-rw-r--r--arch/sparc/kernel/signal.c6
-rw-r--r--arch/sparc/kernel/smp.c6
-rw-r--r--arch/sparc/mm/srmmu.c24
-rw-r--r--arch/sparc64/Makefile14
-rw-r--r--arch/sparc64/boot/Makefile2
-rw-r--r--arch/sparc64/config.in39
-rw-r--r--arch/sparc64/defconfig24
-rw-r--r--arch/sparc64/kernel/Makefile7
-rw-r--r--arch/sparc64/kernel/auxio.c36
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c3
-rw-r--r--arch/sparc64/kernel/central.c129
-rw-r--r--arch/sparc64/kernel/cpu.c9
-rw-r--r--arch/sparc64/kernel/devices.c10
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S4
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S20
-rw-r--r--arch/sparc64/kernel/ebus.c326
-rw-r--r--arch/sparc64/kernel/entry.S203
-rw-r--r--arch/sparc64/kernel/etrap.S225
-rw-r--r--arch/sparc64/kernel/head.S28
-rw-r--r--arch/sparc64/kernel/ioctl32.c168
-rw-r--r--arch/sparc64/kernel/ioport.c15
-rw-r--r--arch/sparc64/kernel/irq.c717
-rw-r--r--arch/sparc64/kernel/process.c77
-rw-r--r--arch/sparc64/kernel/psycho.c1417
-rw-r--r--arch/sparc64/kernel/ptrace.c10
-rw-r--r--arch/sparc64/kernel/rtrap.S163
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/signal.c96
-rw-r--r--arch/sparc64/kernel/signal32.c62
-rw-r--r--arch/sparc64/kernel/smp.c373
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c62
-rw-r--r--arch/sparc64/kernel/sys32.S40
-rw-r--r--arch/sparc64/kernel/sys_sparc.c49
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c386
-rw-r--r--arch/sparc64/kernel/systbls.S391
-rw-r--r--arch/sparc64/kernel/time.c162
-rw-r--r--arch/sparc64/kernel/trampoline.S207
-rw-r--r--arch/sparc64/kernel/traps.c62
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/kernel/unaligned.c56
-rw-r--r--arch/sparc64/kernel/winfixup.S8
-rw-r--r--arch/sparc64/lib/Makefile8
-rw-r--r--arch/sparc64/lib/PeeCeeI.c225
-rw-r--r--arch/sparc64/lib/VISbzero.S34
-rw-r--r--arch/sparc64/lib/VIScopy.S83
-rw-r--r--arch/sparc64/lib/VIScsum.S14
-rw-r--r--arch/sparc64/lib/VIScsumcopy.S880
-rw-r--r--arch/sparc64/lib/VISmemset.S16
-rw-r--r--arch/sparc64/lib/blockops.S10
-rw-r--r--arch/sparc64/lib/checksum.S632
-rw-r--r--arch/sparc64/lib/locks.S27
-rw-r--r--arch/sparc64/lib/strlen_user.S14
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S6
-rw-r--r--arch/sparc64/mm/fault.c55
-rw-r--r--arch/sparc64/mm/init.c277
-rw-r--r--arch/sparc64/mm/ultra.S177
-rw-r--r--arch/sparc64/prom/console.c10
-rw-r--r--arch/sparc64/prom/p1275.c6
-rw-r--r--arch/sparc64/prom/ranges.c77
-rw-r--r--arch/sparc64/prom/tree.c10
-rw-r--r--arch/sparc64/solaris/Makefile26
-rw-r--r--arch/sparc64/solaris/conv.h28
-rw-r--r--arch/sparc64/solaris/entry64.S202
-rw-r--r--arch/sparc64/solaris/fs.c711
-rw-r--r--arch/sparc64/solaris/ioctl.c316
-rw-r--r--arch/sparc64/solaris/ipc.c122
-rw-r--r--arch/sparc64/solaris/misc.c463
-rw-r--r--arch/sparc64/solaris/signal.c419
-rw-r--r--arch/sparc64/solaris/signal.h109
-rw-r--r--arch/sparc64/solaris/socksys.c127
-rw-r--r--arch/sparc64/solaris/systbl.S289
-rw-r--r--arch/sparc64/vmlinux.lds6
203 files changed, 23642 insertions, 4743 deletions
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 6ac472f08..71c310aa1 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -94,9 +94,9 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
tristate 'Parallel port support' CONFIG_PARPORT
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index a36ec98a9..22adc7f62 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -43,7 +43,7 @@ CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_EM86=y
-# CONFIG_PNP_PARPORT is not set
+# CONFIG_PARPORT is not set
#
# Plug and Play support
@@ -67,7 +67,6 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_EZ is not set
# CONFIG_BLK_DEV_HD is not set
@@ -142,6 +141,7 @@ 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
@@ -150,6 +150,8 @@ CONFIG_SCSI_QLOGIC_ISP=y
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
#
# Network device support
@@ -174,6 +176,7 @@ CONFIG_DE4X5=y
# 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_SLIP is not set
@@ -215,6 +218,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
#
# Character devices
@@ -230,12 +234,15 @@ CONFIG_MOUSE=y
# CONFIG_MS_BUSMOUSE is not set
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
#
# Sound
diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c
index 16d7474d1..385fc9494 100644
--- a/arch/alpha/kernel/bios32.c
+++ b/arch/alpha/kernel/bios32.c
@@ -186,6 +186,7 @@ static void layout_dev(struct pci_dev *dev)
pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
if (!base) {
/* this base-address register is unused */
+ dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2] = 0;
continue;
}
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 8f896195d..e22313036 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -437,8 +437,8 @@ entUnaUser:
stq $13,32($30)
stq $14,40($30)
stq $15,48($30)
- bis $31,$30,$19
lda $8,0x3fff
+ addq $30,56,$19
bic $30,$8,$8
jsr $26,do_entUnaUser
ldq $9,0($30)
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index c3838a8bb..12bee3fbc 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -491,8 +491,22 @@ static inline unsigned long s_reg_to_mem (unsigned long s_reg)
| 1L << 0x2c | 1L << 0x2d /* stl stq */ \
| 1L << 0xd ) /* stw */
+#define R(x) ((size_t) &((struct pt_regs *)0)->x)
+
+static int unauser_reg_offsets[32] = {
+ R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
+ /* r9 ... r15 are stored in front of regs. */
+ -56, -48, -40, -32, -24, -16, -8,
+ R(r16), R(r17), R(r18),
+ R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
+ R(r27), R(r28), R(gp),
+ 0, 0
+};
+
+#undef R
+
asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
- unsigned long reg, unsigned long * frame)
+ unsigned long reg, struct pt_regs *regs)
{
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg (unsigned long reg);
@@ -501,12 +515,10 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
static long last_time = 0;
unsigned long tmp1, tmp2, tmp3, tmp4;
- unsigned long *reg_addr, *pc_addr, fake_reg;
+ unsigned long fake_reg, *reg_addr = &fake_reg;
unsigned long uac_bits;
long error;
- pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
-
/* Check the UAC bits to decide what the user wants us to do
with the unaliged access. */
@@ -519,7 +531,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
lock_kernel();
printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
current->comm, current->pid,
- *pc_addr - 4, va, opcode, reg);
+ regs->pc - 4, va, opcode, reg);
unlock_kernel();
}
last_time = jiffies;
@@ -540,51 +552,19 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
++unaligned[1].count;
unaligned[1].va = (unsigned long)va;
- unaligned[1].pc = *pc_addr - 4;
+ unaligned[1].pc = regs->pc - 4;
- reg_addr = frame;
if ((1L << opcode) & OP_INT_MASK) {
/* it's an integer load/store */
- switch (reg) {
- case 0: case 1: case 2: case 3: case 4:
- case 5: case 6: case 7: case 8:
- /* v0-t7 in SAVE_ALL frame */
- reg_addr += 7 + reg;
- break;
-
- case 9: case 10: case 11: case 12:
- case 13: case 14: case 15:
- /* s0-s6 in entUna frame */
- reg_addr += (reg - 9);
- break;
-
- case 16: case 17: case 18:
- /* a0-a2 in PAL frame */
- reg_addr += 7 + 20 + 3 + (reg - 16);
- break;
-
- case 19: case 20: case 21: case 22: case 23:
- case 24: case 25: case 26: case 27: case 28:
- /* a3-at in SAVE_ALL frame */
- reg_addr += 7 + 9 + (reg - 19);
- break;
-
- case 29:
- /* gp in PAL frame */
- reg_addr += 7 + 20 + 2;
- break;
-
- case 30:
+ if (reg < 30) {
+ reg_addr = (unsigned long *)
+ ((char *)regs + unauser_reg_offsets[reg]);
+ } else if (reg == 30) {
/* usp in PAL regs */
fake_reg = rdusp();
- reg_addr = &fake_reg;
- break;
-
- case 31:
+ } else {
/* zero "register" */
fake_reg = 0;
- reg_addr = &fake_reg;
- break;
}
}
@@ -728,7 +708,6 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
case 0x26: /* sts */
fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
- reg_addr = &fake_reg;
/* FALLTHRU */
case 0x2c: /* stl */
@@ -763,7 +742,6 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
case 0x27: /* stt */
fake_reg = alpha_read_fp_reg(reg);
- reg_addr = &fake_reg;
/* FALLTHRU */
case 0x2d: /* stq */
@@ -807,14 +785,14 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
return;
give_sigsegv:
- *pc_addr -= 4; /* make pc point to faulting insn */
+ regs->pc -= 4; /* make pc point to faulting insn */
lock_kernel();
force_sig(SIGSEGV, current);
unlock_kernel();
return;
give_sigbus:
- *pc_addr -= 4;
+ regs->pc -= 4;
lock_kernel();
force_sig(SIGBUS, current);
unlock_kernel();
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 887407c61..50d9de2a7 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -23,8 +23,10 @@ comment 'General setup'
bool 'Kernel math emulation' CONFIG_MATH_EMULATION
bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
+bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' PCI BIOS support' CONFIG_PCI_BIOS
+ bool ' PCI direct access support' CONFIG_PCI_DIRECT
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
fi
@@ -36,7 +38,7 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
choice 'Processor type' \
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index e3e50886c..93f300de7 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -20,6 +20,8 @@ CONFIG_MODULES=y
# CONFIG_MATH_EMULATION is not set
CONFIG_NET=y
CONFIG_PCI=y
+CONFIG_PCI_BIOS=y
+# CONFIG_PCI_DIRECT is not set
# CONFIG_MCA is not set
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
@@ -139,7 +141,6 @@ CONFIG_SCSI_OMIT_FLASHPOINT=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 is not set
@@ -160,6 +161,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
@@ -172,7 +174,6 @@ CONFIG_EEXPRESS_PRO100=y
# 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_SLIP is not set
@@ -214,6 +215,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_AUTOFS_FS=y
# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
#
# Character devices
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index 8f7a796fe..d1d7a85e0 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -1,7 +1,7 @@
/*
* bios32.c - BIOS32, PCI BIOS functions.
*
- * $Id: bios32.c,v 1.1.1.1 1997/06/01 03:16:32 ralf Exp $
+ * $Id: bios32.c,v 1.2 1997/07/20 14:57:08 ralf Exp $
*
* Sponsored by
* iX Multiuser Multitasking Magazine
@@ -61,6 +61,9 @@
*
* Jun 20, 1997 : Corrected problems in "conf1" type accesses.
* (paubert@iram.es)
+ *
+ * Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts
+ * and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*/
#include <linux/config.h>
@@ -75,69 +78,12 @@
#include <asm/system.h>
#include <asm/io.h>
-#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
-#define PCIBIOS_FIND_PCI_DEVICE 0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
-#define PCIBIOS_READ_CONFIG_BYTE 0xb108
-#define PCIBIOS_READ_CONFIG_WORD 0xb109
-#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
-
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
-/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * Standard BIOS 32-bit Service Directory Proposal
- * Revision 0.4 May 24, 1993
- * Phoenix Technologies Ltd.
- * Norwood, MA
- * and the PCI BIOS specification.
- */
-
-union bios32 {
- struct {
- unsigned long signature; /* _32_ */
- unsigned long entry; /* 32 bit physical address */
- unsigned char revision; /* Revision level, 0 */
- unsigned char length; /* Length in paragraphs should be 01 */
- unsigned char checksum; /* All bytes must add up to zero */
- unsigned char reserved[5]; /* Must be zero */
- } fields;
- char chars[16];
-};
-
-#ifdef CONFIG_PCI
/*
- * Physical address of the service directory. I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
+ * Generic PCI access -- indirect calls according to detected HW.
*/
-static unsigned long bios32_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} bios32_indirect = { 0, KERNEL_CS };
-
-
-/*
- * function table for accessing PCI configuration space
- */
struct pci_access {
+ int pci_present;
int (*find_device)(unsigned short, unsigned short, unsigned short, unsigned char *, unsigned char *);
int (*find_class)(unsigned int, unsigned short, unsigned char *, unsigned char *);
int (*read_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char *);
@@ -148,363 +94,137 @@ struct pci_access {
int (*write_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int);
};
-/*
- * pointer to selected PCI access function table
- */
-static struct pci_access *access_pci = NULL;
-
-
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
+static int pci_stub(void)
{
- unsigned char return_code; /* %al */
- unsigned long address; /* %ebx */
- unsigned long length; /* %ecx */
- unsigned long entry; /* %edx */
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)"
- : "=a" (return_code),
- "=b" (address),
- "=c" (length),
- "=d" (entry)
- : "0" (service),
- "1" (0),
- "D" (&bios32_indirect));
- restore_flags(flags);
-
- switch (return_code) {
- case 0:
- return address + entry;
- case 0x80: /* Not present */
- printk("bios32_service(0x%lx) : not present\n", service);
- return 0;
- default: /* Shouldn't happen */
- printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
- service, return_code);
- return 0;
- }
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
}
-static long pcibios_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} pci_indirect = { 0, KERNEL_CS };
+static struct pci_access pci_access_none = {
+ 0, /* No PCI present */
+ (void *) pci_stub, /* No functions implemented */
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub
+};
+static struct pci_access *access_pci = &pci_access_none;
-__initfunc(static int check_pcibios(void))
+int pcibios_present(void)
{
- unsigned long signature;
- unsigned char present_status;
- unsigned char major_revision;
- unsigned char minor_revision;
- unsigned long flags;
- int pack;
-
- if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
- pci_indirect.address = pcibios_entry | PAGE_OFFSET;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:\tshl $8, %%eax\n\t"
- "movw %%bx, %%ax"
- : "=d" (signature),
- "=a" (pack)
- : "1" (PCIBIOS_PCI_BIOS_PRESENT),
- "D" (&pci_indirect)
- : "bx", "cx");
- restore_flags(flags);
-
- present_status = (pack >> 16) & 0xff;
- major_revision = (pack >> 8) & 0xff;
- minor_revision = pack & 0xff;
- if (present_status || (signature != PCI_SIGNATURE)) {
- printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
- " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
- " and signature of 0x%08lx (%c%c%c%c). mail drew@Colorado.EDU\n",
- (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
- present_status, signature,
- (char) (signature >> 0), (char) (signature >> 8),
- (char) (signature >> 16), (char) (signature >> 24));
-
- if (signature != PCI_SIGNATURE)
- pcibios_entry = 0;
- }
- 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 0;
+ return access_pci->pci_present;
}
-
-static int pci_bios_find_class (unsigned int class_code, unsigned short index,
+int pcibios_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *device_fn)
{
- unsigned long bx;
- unsigned long ret;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__ ("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
- "c" (class_code),
- "S" ((int) index),
- "D" (&pci_indirect));
- restore_flags(flags);
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->find_class(class_code, index, bus, device_fn);
}
-
-static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus, unsigned char *device_fn)
{
- unsigned short bx;
- unsigned short ret;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_DEVICE),
- "c" (device_id),
- "d" (vendor),
- "S" ((int) index),
- "D" (&pci_indirect));
- restore_flags(flags);
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->find_device(vendor, device_id, index, bus, device_fn);
}
-static int pci_bios_read_config_byte(unsigned char bus,
+int pcibios_read_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_BYTE),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_byte(bus, device_fn, where, value);
}
-static int pci_bios_read_config_word (unsigned char bus,
+int pcibios_read_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_WORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_word(bus, device_fn, where, value);
}
-static int pci_bios_read_config_dword (unsigned char bus,
+int pcibios_read_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_DWORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_dword(bus, device_fn, where, value);
}
-static int pci_bios_write_config_byte (unsigned char bus,
+int pcibios_write_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_byte(bus, device_fn, where, value);
}
-static int pci_bios_write_config_word (unsigned char bus,
+int pcibios_write_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_WORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_word(bus, device_fn, where, value);
}
-static int pci_bios_write_config_dword (unsigned char bus,
+int pcibios_write_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_dword(bus, device_fn, where, value);
}
/*
- * function table for BIOS32 access
+ * Direct access to PCI hardware...
*/
-static struct pci_access pci_bios_access = {
- pci_bios_find_device,
- pci_bios_find_class,
- pci_bios_read_config_byte,
- pci_bios_read_config_word,
- pci_bios_read_config_dword,
- pci_bios_write_config_byte,
- pci_bios_write_config_word,
- pci_bios_write_config_dword
-};
-
-
/*
* Given the vendor and device ids, find the n'th instance of that device
* in the system.
*/
+
+#ifdef CONFIG_PCI_DIRECT
+
static int pci_direct_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus,
unsigned char *devfn)
{
unsigned int curr = 0;
struct pci_dev *dev;
- unsigned long flags;
- save_flags(flags);
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->vendor == vendor && dev->device == device_id) {
if (curr == index) {
*devfn = dev->devfn;
*bus = dev->bus->number;
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
++curr;
}
}
- restore_flags(flags);
return PCIBIOS_DEVICE_NOT_FOUND;
}
-
/*
* Given the class, find the n'th instance of that device
* in the system.
*/
+
static int pci_direct_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *devfn)
{
unsigned int curr = 0;
struct pci_dev *dev;
- unsigned long flags;
- save_flags(flags); cli();
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->class == class_code) {
if (curr == index) {
*devfn = dev->devfn;
*bus = dev->bus->number;
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
++curr;
}
}
- restore_flags(flags);
return PCIBIOS_DEVICE_NOT_FOUND;
}
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
+
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
@@ -585,10 +305,8 @@ static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device
#undef CONFIG_CMD
-/*
- * functiontable for type 1
- */
static struct pci_access pci_direct_conf1 = {
+ 1,
pci_direct_find_device,
pci_direct_find_class,
pci_conf1_read_config_byte,
@@ -602,6 +320,7 @@ static struct pci_access pci_direct_conf1 = {
/*
* Functions for accessing PCI configuration space with type 2 accesses
*/
+
#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where)
#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0)
@@ -698,10 +417,8 @@ static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device
#undef IOADDR
#undef FUNC
-/*
- * functiontable for type 2
- */
static struct pci_access pci_direct_conf2 = {
+ 1,
pci_direct_find_device,
pci_direct_find_class,
pci_conf2_read_config_byte,
@@ -712,8 +429,7 @@ static struct pci_access pci_direct_conf2 = {
pci_conf2_write_config_dword
};
-
-__initfunc(static struct pci_access *check_direct_pci(void))
+__initfunc(static struct pci_access *pci_check_direct(void))
{
unsigned int tmp;
unsigned long flags;
@@ -721,7 +437,7 @@ __initfunc(static struct pci_access *check_direct_pci(void))
save_flags(flags); cli();
/*
- * check if configuration type 1 works
+ * Check if configuration type 1 works.
*/
outb (0x01, 0xCFB);
tmp = inl (0xCF8);
@@ -729,153 +445,385 @@ __initfunc(static struct pci_access *check_direct_pci(void))
if (inl (0xCF8) == 0x80000000) {
outl (tmp, 0xCF8);
restore_flags(flags);
- printk("pcibios_init: Using configuration type 1\n");
+ printk("PCI: Using configuration type 1\n");
return &pci_direct_conf1;
}
outl (tmp, 0xCF8);
/*
- * check if configuration type 2 works
+ * Check if configuration type 2 works.
*/
outb (0x00, 0xCFB);
outb (0x00, 0xCF8);
outb (0x00, 0xCFA);
if (inb (0xCF8) == 0x00 && inb (0xCFB) == 0x00) {
restore_flags(flags);
- printk("pcibios_init: Using configuration type 2\n");
+ printk("PCI: Using configuration type 2\n");
return &pci_direct_conf2;
}
restore_flags(flags);
- printk("pcibios_init: Not supported chipset for direct PCI access !\n");
+ printk("PCI: PCI hardware not found (i.e., not present or not supported).\n");
return NULL;
}
+#endif
/*
- * access defined pcibios functions via
- * the function table
+ * BIOS32 and PCI BIOS handling.
*/
-int pcibios_present(void)
+#ifdef CONFIG_PCI_BIOS
+
+#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
+#define PCIBIOS_FIND_PCI_DEVICE 0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
+#define PCIBIOS_READ_CONFIG_BYTE 0xb108
+#define PCIBIOS_READ_CONFIG_WORD 0xb109
+#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ * Standard BIOS 32-bit Service Directory Proposal
+ * Revision 0.4 May 24, 1993
+ * Phoenix Technologies Ltd.
+ * Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+ struct {
+ unsigned long signature; /* _32_ */
+ unsigned long entry; /* 32 bit physical address */
+ unsigned char revision; /* Revision level, 0 */
+ unsigned char length; /* Length in paragraphs should be 01 */
+ unsigned char checksum; /* All bytes must add up to zero */
+ unsigned char reserved[5]; /* Must be zero */
+ } fields;
+ char chars[16];
+};
+
+/*
+ * Physical address of the service directory. I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static unsigned long bios32_entry = 0;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} bios32_indirect = { 0, KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
{
- return access_pci ? 1 : 0;
+ unsigned char return_code; /* %al */
+ unsigned long address; /* %ebx */
+ unsigned long length; /* %ecx */
+ unsigned long entry; /* %edx */
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)"
+ : "=a" (return_code),
+ "=b" (address),
+ "=c" (length),
+ "=d" (entry)
+ : "0" (service),
+ "1" (0),
+ "D" (&bios32_indirect));
+ restore_flags(flags);
+
+ switch (return_code) {
+ case 0:
+ return address + entry;
+ case 0x80: /* Not present */
+ printk("bios32_service(0x%lx): not present\n", service);
+ return 0;
+ default: /* Shouldn't happen */
+ printk("bios32_service(0x%lx): returned 0x%x, mail drew@colorado.edu\n",
+ service, return_code);
+ return 0;
+ }
}
-int pcibios_find_class (unsigned int class_code, unsigned short index,
+static long pcibios_entry = 0;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} pci_indirect = { 0, KERNEL_CS };
+
+__initfunc(static int check_pcibios(void))
+{
+ unsigned long signature;
+ unsigned char present_status;
+ unsigned char major_revision;
+ unsigned char minor_revision;
+ unsigned long flags;
+ int pack;
+
+ if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+ pci_indirect.address = pcibios_entry | PAGE_OFFSET;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:\tshl $8, %%eax\n\t"
+ "movw %%bx, %%ax"
+ : "=d" (signature),
+ "=a" (pack)
+ : "1" (PCIBIOS_PCI_BIOS_PRESENT),
+ "D" (&pci_indirect)
+ : "bx", "cx");
+ restore_flags(flags);
+
+ present_status = (pack >> 16) & 0xff;
+ major_revision = (pack >> 8) & 0xff;
+ minor_revision = pack & 0xff;
+ if (present_status || (signature != PCI_SIGNATURE)) {
+ printk ("PCI: %s: BIOS32 Service Directory says PCI BIOS is present,\n"
+ " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
+ " and signature of 0x%08lx (%c%c%c%c). Mail drew@Colorado.EDU\n",
+ (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
+ present_status, signature,
+ (char) (signature >> 0), (char) (signature >> 8),
+ (char) (signature >> 16), (char) (signature >> 24));
+
+ if (signature != PCI_SIGNATURE)
+ pcibios_entry = 0;
+ }
+ if (pcibios_entry) {
+ printk ("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
+ major_revision, minor_revision, pcibios_entry);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pci_bios_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *device_fn)
{
- if (access_pci && access_pci->find_class)
- return access_pci->find_class(class_code, index, bus, device_fn);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long bx;
+ unsigned long ret;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__ ("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=b" (bx),
+ "=a" (ret)
+ : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
+ "c" (class_code),
+ "S" ((int) index),
+ "D" (&pci_indirect));
+ restore_flags(flags);
+ *bus = (bx >> 8) & 0xff;
+ *device_fn = bx & 0xff;
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus, unsigned char *device_fn)
{
- if (access_pci && access_pci->find_device)
- return access_pci->find_device(vendor, device_id, index, bus, device_fn);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned short bx;
+ unsigned short ret;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=b" (bx),
+ "=a" (ret)
+ : "1" (PCIBIOS_FIND_PCI_DEVICE),
+ "c" (device_id),
+ "d" (vendor),
+ "S" ((int) index),
+ "D" (&pci_indirect));
+ restore_flags(flags);
+ *bus = (bx >> 8) & 0xff;
+ *device_fn = bx & 0xff;
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_byte (unsigned char bus,
+static int pci_bios_read_config_byte(unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char *value)
{
- if (access_pci && access_pci->read_config_byte)
- return access_pci->read_config_byte(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_BYTE),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_word (unsigned char bus,
+static int pci_bios_read_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short *value)
{
- if (access_pci && access_pci->read_config_word)
- return access_pci->read_config_word(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_WORD),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_dword (unsigned char bus,
+static int pci_bios_read_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int *value)
{
- if (access_pci && access_pci->read_config_dword)
- return access_pci->read_config_dword(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_DWORD),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_write_config_byte (unsigned char bus,
+static int pci_bios_write_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char value)
{
- if (access_pci && access_pci->write_config_byte)
- return access_pci->write_config_byte(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_write_config_word (unsigned char bus,
+static int pci_bios_write_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short value)
{
- if (access_pci && access_pci->write_config_word)
- return access_pci->write_config_word(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
-}
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
-int pcibios_write_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned int value)
-{
- if (access_pci && access_pci->write_config_dword)
- return access_pci->write_config_dword(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_WORD),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-const char *pcibios_strerror (int error)
+static int pci_bios_write_config_dword (unsigned char bus,
+ unsigned char device_fn, unsigned char where, unsigned int value)
{
- static char buf[80];
-
- switch (error) {
- case PCIBIOS_SUCCESSFUL:
- return "SUCCESSFUL";
-
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return "FUNC_NOT_SUPPORTED";
-
- case PCIBIOS_BAD_VENDOR_ID:
- return "SUCCESSFUL";
-
- case PCIBIOS_DEVICE_NOT_FOUND:
- return "DEVICE_NOT_FOUND";
-
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return "BAD_REGISTER_NUMBER";
-
- case PCIBIOS_SET_FAILED:
- return "SET_FAILED";
-
- case PCIBIOS_BUFFER_TOO_SMALL:
- return "BUFFER_TOO_SMALL";
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
- default:
- sprintf (buf, "UNKNOWN RETURN 0x%x", error);
- return buf;
- }
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
+/*
+ * Function table for BIOS32 access
+ */
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
-{
- return mem_start;
-}
+static struct pci_access pci_bios_access = {
+ 1,
+ pci_bios_find_device,
+ pci_bios_find_class,
+ pci_bios_read_config_byte,
+ pci_bios_read_config_word,
+ pci_bios_read_config_dword,
+ pci_bios_write_config_byte,
+ pci_bios_write_config_word,
+ pci_bios_write_config_dword
+};
-#endif
+/*
+ * Try to find PCI BIOS.
+ */
-__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static struct pci_access *pci_find_bios(void))
{
-#ifdef CONFIG_PCI
union bios32 *check;
unsigned char sum;
int i, length;
@@ -884,7 +832,6 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
- *
*/
for (check = (union bios32 *) __va(0xe0000);
@@ -901,24 +848,59 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
if (sum != 0)
continue;
if (check->fields.revision != 0) {
- printk("pcibios_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
+ printk("PCI: unsupported BIOS32 revision %d at 0x%p, mail drew@colorado.edu\n",
check->fields.revision, check);
continue;
}
- printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
- if (!bios32_entry) {
- if (check->fields.entry >= 0x100000) {
- printk("pcibios_init: entry in high memory, trying direct PCI access\n");
- access_pci = check_direct_pci();
- } else {
- 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;
- }
+ printk ("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+ if (check->fields.entry >= 0x100000) {
+#ifdef CONFIG_PCI_DIRECT
+ printk("PCI: BIOS32 entry in high memory, trying direct PCI access.\n");
+ return pci_check_direct();
+#else
+ printk("PCI: BIOS32 entry in high memory, cannot use.\n");
+#endif
+ } else {
+ bios32_entry = check->fields.entry;
+ printk ("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+ bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+ if (check_pcibios())
+ return &pci_bios_access;
}
+ break; /* Hopefully more than one BIOS32 cannot happen... */
}
- if (bios32_entry && check_pcibios())
- access_pci = &pci_bios_access;
+
+ return NULL;
+}
+
#endif
+
+/*
+ * No fixup function used.
+ */
+
+__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+{
+ return mem_start;
+}
+
+/*
+ * Initialization. Try all known PCI access methods.
+ */
+
+__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+{
+ struct pci_access *a = NULL;
+
+#ifdef CONFIG_PCI_BIOS
+ a = pci_find_bios();
+#else
+#ifdef CONFIG_PCI_DIRECT
+ a = pci_check_direct();
+#endif
+#endif
+ if (a)
+ access_pci = a;
+
return memory_start;
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index e7b9e0779..21bf04709 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -373,7 +373,7 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_mknod)
.long SYMBOL_NAME(sys_chmod) /* 15 */
.long SYMBOL_NAME(sys_chown)
- .long SYMBOL_NAME(sys_break)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
.long SYMBOL_NAME(sys_stat)
.long SYMBOL_NAME(sys_lseek)
.long SYMBOL_NAME(sys_getpid) /* 20 */
@@ -387,11 +387,11 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_fstat)
.long SYMBOL_NAME(sys_pause)
.long SYMBOL_NAME(sys_utime) /* 30 */
- .long SYMBOL_NAME(sys_stty)
- .long SYMBOL_NAME(sys_gtty)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
.long SYMBOL_NAME(sys_access)
.long SYMBOL_NAME(sys_nice)
- .long SYMBOL_NAME(sys_ftime) /* 35 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */
.long SYMBOL_NAME(sys_sync)
.long SYMBOL_NAME(sys_kill)
.long SYMBOL_NAME(sys_rename)
@@ -400,7 +400,7 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_dup)
.long SYMBOL_NAME(sys_pipe)
.long SYMBOL_NAME(sys_times)
- .long SYMBOL_NAME(sys_prof)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
.long SYMBOL_NAME(sys_brk) /* 45 */
.long SYMBOL_NAME(sys_setgid)
.long SYMBOL_NAME(sys_getgid)
@@ -408,13 +408,13 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_geteuid)
.long SYMBOL_NAME(sys_getegid) /* 50 */
.long SYMBOL_NAME(sys_acct)
- .long SYMBOL_NAME(sys_phys)
- .long SYMBOL_NAME(sys_lock)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old phys syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
.long SYMBOL_NAME(sys_ioctl)
.long SYMBOL_NAME(sys_fcntl) /* 55 */
- .long SYMBOL_NAME(sys_mpx)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
.long SYMBOL_NAME(sys_setpgid)
- .long SYMBOL_NAME(sys_ulimit)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
.long SYMBOL_NAME(sys_olduname)
.long SYMBOL_NAME(sys_umask) /* 60 */
.long SYMBOL_NAME(sys_chroot)
@@ -454,7 +454,7 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_fchown) /* 95 */
.long SYMBOL_NAME(sys_getpriority)
.long SYMBOL_NAME(sys_setpriority)
- .long SYMBOL_NAME(sys_profil)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
.long SYMBOL_NAME(sys_statfs)
.long SYMBOL_NAME(sys_fstatfs) /* 100 */
.long SYMBOL_NAME(sys_ioperm)
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index bd4bf56cf..ef2cfa9a2 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -312,15 +312,16 @@ ignore_int:
pushl %eax
pushl %ecx
pushl %edx
+ push %es
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
+ pop %es
popl %edx
popl %ecx
popl %eax
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index a711d9a40..b740eb0ce 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -7,6 +7,7 @@
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -49,6 +50,7 @@ EXPORT_SYMBOL_NOVERS(kernel_flag);
EXPORT_SYMBOL_NOVERS(active_kernel_processor);
EXPORT_SYMBOL(smp_invalidate_needed);
EXPORT_SYMBOL_NOVERS(__lock_kernel);
+EXPORT_SYMBOL(lk_lockmsg);
/* Global SMP irq stuff */
EXPORT_SYMBOL(synchronize_irq);
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 2e0f3e084..62d074508 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -42,8 +42,6 @@
extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
#endif
-#define CR0_NE 32
-
unsigned int local_irq_count[NR_CPUS];
#ifdef __SMP__
atomic_t __intel_bh_counter;
@@ -55,6 +53,8 @@ int __intel_bh_counter;
static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
#endif
+atomic_t nmi_counter;
+
/*
* This contains the irq mask for both irq controllers
*/
@@ -199,7 +199,6 @@ static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
* be shot.
*/
-
static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
outb(0,0xF0);
@@ -224,28 +223,26 @@ static struct irqaction *irq_action[16] = {
int get_irq_list(char *buf)
{
- int i, len = 0;
+ int i;
struct irqaction * action;
+ char *p = buf;
for (i = 0 ; i < NR_IRQS ; i++) {
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %10u %s",
+ p += sprintf(p, "%3d: %10u %s",
i, kstat.interrupts[i], action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
+ p += sprintf(p, ", %s", action->name);
}
- len += sprintf(buf+len, "\n");
+ *p++ = '\n';
}
-/*
- * Linus - should you add NMI counts here ?????
- */
+ p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
#ifdef __SMP_PROF__
- len+=sprintf(buf+len, "IPI: %8lu received\n",
- ipi_count);
+ p += sprintf(p, "IPI: %10lu\n", ipi_count);
#endif
- return len;
+ return p - buf;
}
#ifdef __SMP_PROF__
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index d187128e1..eef030375 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -85,7 +85,7 @@ extern void update_one_process( struct task_struct *p,
* 5AP. Remote read is never used
* 9AP. XXX NEED TO CHECK WE HANDLE THIS XXX
* 10AP. XXX NEED TO CHECK WE HANDLE THIS XXX
- * 11AP. Linux read the APIC between writes to avoid this, as per
+ * 11AP. Linux reads the APIC between writes to avoid this, as per
* the documentation. Make sure you preserve this as it affects
* the C stepping chips too.
*
@@ -887,10 +887,14 @@ __initfunc(void smp_boot_cpus(void))
/*
* Initialize the logical to physical cpu number mapping
+ * and the per-CPU profiling counter/multiplier
*/
- for (i = 0; i < NR_CPUS; i++)
+ for (i = 0; i < NR_CPUS; i++) {
cpu_number_map[i] = -1;
+ prof_counter[i] = 1;
+ prof_multiplier[i] = 1;
+ }
/*
* Setup boot CPU information
@@ -917,15 +921,8 @@ __initfunc(void smp_boot_cpus(void))
* of here now!
*/
- if (!smp_found_config) {
- /*
- * For SMP-simulation on one CPU to work, we must initialize these
- * values for the single CPU here:
- */
- prof_counter[0] = prof_multiplier[0] = 1;
-
+ if (!smp_found_config)
return;
- }
/*
* Map the local APIC into kernel space
@@ -1625,7 +1622,6 @@ static unsigned int calibration_result;
__initfunc(void setup_APIC_clock (void))
{
- int cpu = smp_processor_id();
unsigned long flags;
static volatile int calibration_lock;
@@ -1658,11 +1654,10 @@ __initfunc(void setup_APIC_clock (void))
}
/*
- * Now set up the timer for real. Profiling multiplier is 1.
+ * Now set up the timer for real.
*/
- setup_APIC_timer (calibration_result);
- prof_counter[cpu] = prof_multiplier[cpu] = 1;
+ setup_APIC_timer (calibration_result);
/*
* We ACK the APIC, just in case there is something pending.
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index b1eb2911d..f43dfe726 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -17,6 +17,7 @@
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/file.h>
+#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
@@ -203,3 +204,45 @@ out:
unlock_kernel();
return ret;
}
+
+/*
+ * Old cruft
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ return 0;
+ return -EFAULT;
+}
+
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+ int error;
+
+ if (!name)
+ return -EFAULT;
+ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+ error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ error -= __put_user(0,name->release+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ error -= __put_user(0,name->version+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ error = __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = error ? -EFAULT : 0;
+
+ return error;
+}
+
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index b397fc76d..6fb18dc35 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -29,6 +29,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/spinlock.h>
+#include <asm/atomic.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
@@ -271,7 +272,9 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
unsigned char reason = inb(0x61);
+ extern atomic_t nmi_counter;
+ atomic_inc(&nmi_counter);
if (reason & 0x80)
mem_parity_error(reason, regs);
if (reason & 0x40)
@@ -348,7 +351,10 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
long error_code)
{
+#if 0
+ /* No need to warn about this any longer. */
printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+#endif
}
/*
diff --git a/arch/i386/lib/checksum.c b/arch/i386/lib/checksum.c
index 4a0f82440..2293a6c5e 100644
--- a/arch/i386/lib/checksum.c
+++ b/arch/i386/lib/checksum.c
@@ -111,13 +111,13 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
#define SRC(y...) \
" 9999: "#y"; \n \
.section __ex_table, \"a\"; \n \
- .long 9999b, src_access_fault \n \
+ .long 9999b, 6001f \n \
.previous"
#define DST(y...) \
" 9999: "#y"; \n \
.section __ex_table, \"a\"; \n \
- .long 9999b, dst_access_fault \n \
+ .long 9999b, 6002f \n \
.previous"
unsigned int csum_partial_copy_generic (const char *src, char *dst,
@@ -203,28 +203,28 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
adcl $0, %%eax
7:
-end_of_body:
+5000:
# Exception handler:
################################################
#
.section .fixup, \"a\" #
#
-common_fixup: #
+6000: #
#
movl %7, (%%ebx) #
#
# FIXME: do zeroing of rest of the buffer here. #
#
- jmp end_of_body #
+ jmp 5000b #
#
-src_access_fault: #
+6001: #
movl %1, %%ebx #
- jmp common_fixup #
+ jmp 6000b #
#
-dst_access_fault: #
+6002: #
movl %2, %%ebx #
- jmp common_fixup #
+ jmp 6000b #
#
.previous #
#
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index e4847c070..8181fd6c7 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -186,16 +186,15 @@ bad_area:
*
* First we check if it was the bootup rw-test, though..
*/
- if (wp_works_ok < 0 && address == 0xc0000000 && (error_code & 1)) {
+ if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
wp_works_ok = 1;
- pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
+ pg0[0] = pte_val(mk_pte(TASK_SIZE, PAGE_SHARED));
flush_tlb();
goto out;
}
- if (address < PAGE_SIZE) {
+ if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
- } else
+ else
printk(KERN_ALERT "Unable to handle kernel paging request");
printk(" at virtual address %08lx\n",address);
__asm__("movl %%cr3,%0" : "=r" (page));
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 8f2852a48..6ed47e2ef 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -261,6 +261,43 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
return free_area_init(start_mem, end_mem);
}
+/*
+ * Test if the WP bit works in supervisor mode. It isn't supported on 386's
+ * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps
+ * before and after the test are here to work-around some nasty CPU bugs.
+ */
+
+__initfunc(void test_wp_bit(void))
+{
+ unsigned char tmp_reg;
+ unsigned long old = pg0[0];
+
+ printk("Checking if this processor honours the WP bit even in supervisor mode... ");
+ pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
+ local_flush_tlb();
+ current->mm->mmap->vm_start += PAGE_SIZE;
+ __asm__ __volatile__(
+ "jmp 1f; 1:\n"
+ "movb %0,%1\n"
+ "movb %1,%0\n"
+ "jmp 1f; 1:\n"
+ :"=m" (*(char *) __va(0)),
+ "=q" (tmp_reg)
+ :/* no inputs */
+ :"memory");
+ pg0[0] = old;
+ local_flush_tlb();
+ current->mm->mmap->vm_start -= PAGE_SIZE;
+ if (wp_works_ok < 0) {
+ wp_works_ok = 0;
+ printk("No.\n");
+#ifndef CONFIG_M386
+ panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
+#endif
+ } else
+ printk("Ok.\n");
+}
+
__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
unsigned long start_low_mem = PAGE_SIZE;
@@ -339,30 +376,9 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10));
-/* test if the WP bit is honoured in supervisor mode */
- if (wp_works_ok < 0) {
- unsigned char tmp_reg;
- unsigned long old = pg0[0];
- printk("Checking if this processor honours the WP bit even in supervisor mode... ");
- pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
- local_flush_tlb();
- current->mm->mmap->vm_start += PAGE_SIZE;
- __asm__ __volatile__(
- "movb %0,%1 ; movb %1,%0"
- :"=m" (*(char *) __va(0)),
- "=q" (tmp_reg)
- :/* no inputs */
- :"memory");
- pg0[0] = old;
- local_flush_tlb();
- current->mm->mmap->vm_start -= PAGE_SIZE;
- if (wp_works_ok < 0) {
- wp_works_ok = 0;
- printk("No.\n");
- } else
- printk("Ok.\n");
- }
- return;
+
+ if (wp_works_ok < 0)
+ test_wp_bit();
}
void free_initmem(void)
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index 2390fb6fc..25d6ded04 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -52,9 +52,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-fi
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_AMIGA" = "y" ]; then
bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 67d87c1b9..a4fc10ab0 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -13,7 +13,7 @@
all: kernel.o head.o
O_TARGET := kernel.o
O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
- setup.o bios32.o sys_m68k.o time.o
+ setup.o sys_m68k.o time.o
ifdef CONFIG_VT
O_OBJS += console.o
endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 27883a86e..f07a6a038 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -65,7 +65,7 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;){
- if (!need_resched)
+ if (!resched_needed())
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index be4149cbb..6b660118a 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -526,7 +526,7 @@ asmlinkage void syscall_trace(void)
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 52c13445d..ab887801c 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -441,7 +441,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
regs->pc -= 2;
}
}
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code)) {
discard_frame:
@@ -489,7 +489,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 516baec29..b1df65c86 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -13,21 +13,21 @@
# Copyright (C) 1994, 1995, 1996 by Ralf Baechle
# DECStation modifications by Paul M. Antoine, 1996
#
-# $Id: Makefile,v 1.5 1997/07/01 08:54:40 ralf Exp $
+# $Id: Makefile,v 1.7 1997/08/30 04:51:27 ralf Exp $
#
#
# Select the object file format to substitute into the linker script.
#
ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE = mipsel-linux-
+tool-prefix = mipsel-linux-
ifdef CONFIG_MIPS_ECOFF
oformat = ecoff-littlemips
else
oformat = elf32-littlemips
endif
else
-CROSS_COMPILE = mips-linux-
+tool-prefix = mips-linux-
ifdef CONFIG_MIPS_ECOFF
oformat = ecoff-bigmips
else
@@ -35,6 +35,10 @@ oformat = elf32-bigmips
endif
endif
+ifdef CONFIG_CROSSCOMPILE
+CROSS_COMPILE = $(tool-prefix)
+endif
+
LINKFLAGS = -static -N
MODFLAGS += -mlong-calls
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 35903797a..9e820f29e 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -21,10 +21,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
-if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
- "$CONFIG_OLIVETTI_M700" = "y" ]; then
- define_bool CONFIG_VIDEO_G364 y
-fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Support for SGI workstations' CONFIG_SGI
if [ "$CONFIG_SGI" = "y" ]; then
@@ -32,6 +28,21 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
fi
bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+
+#
+# Select some configuration options automatically for certain systems.
+#
+unset CONFIG_PCI
+unset CONFIG_MIPS_JAZZ
+unset CONFIG_VIDEO_G364
+
+if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
+ define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
+ "$CONFIG_OLIVETTI_M700" = "y" ]; then
+ define_bool CONFIG_VIDEO_G364 y
+fi
if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \
"$CONFIG_DESKSTATION_TYNE" = "y" ]; then
define_bool CONFIG_MIPS_ARC y
@@ -41,9 +52,7 @@ if [ "$CONFIG_ACER_PICA_61" = "y" -o \
"$CONFIG_MIPS_MAGNUM_4000" = "y" ]; then
define_bool CONFIG_MIPS_JAZZ y
fi
-unset CONFIG_PCI
-if [ "$CONFIG_SNI_RM200_PCI" = "y" -o \
- "$CONFIG_ALGOR_P4032" = "y" ]; then
+if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
define_bool CONFIG_PCI y
fi
endmenu
@@ -70,15 +79,19 @@ else
define_bool CONFIG_ELF_KERNEL y
bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
fi
+
if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
define_bool CONFIG_BINFMT_IRIX y
define_bool CONFIG_FORWARD_KEYBOARD y
fi
-define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_BINFMT_AOUT n
+define_bool CONFIG_BINFMT_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
+
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
@@ -208,6 +221,10 @@ mainmenu_option next_comment
comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE
+fi
bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
bool 'Kernel profiling support' CONFIG_PROFILE
if [ "$CONFIG_PROFILE" = "y" ]; then
diff --git a/arch/mips/dec/decstation.S b/arch/mips/dec/decstation.S
index a5a4f9b6d..612fcea0b 100644
--- a/arch/mips/dec/decstation.S
+++ b/arch/mips/dec/decstation.S
@@ -14,6 +14,8 @@
* the end hasn't been modified to suit the DECStation's interrupts.
* (Paul, you need to fix this file to comply with NAPS. Won't be
* too hard - Ralf)
+ *
+ * $Id:$
*/
#include <asm/asm.h>
#include <asm/mipsconfig.h>
@@ -223,12 +225,12 @@ loc_scsi: PANIC("Unimplemented loc_scsi handler")
* comment - Ralf)
* Andy, 6/16/95
*/
-loc_ethernet: PANIC("Unimplemented loc_ethernet\n")
+loc_ethernet: PANIC("Unimplemented loc_ethernet")
/*
* Keyboard interrupt, remapped to level 1
*/
-loc_keyboard: PANIC("Unimplemented loc_keyboard\n")
+loc_keyboard: PANIC("Unimplemented loc_keyboard")
loc_mouse: PANIC("Unimplemented loc_mouse handler")
@@ -291,7 +293,7 @@ ll_rtc: PANIC("Unimplemented RTC interrupt handler")
* Timer IRQ
* We remap the timer irq to be more similar to a IBM compatible
*/
-ll_timer: PANIC("Timer interrupt!\n");
+ll_timer: PANIC("Timer interrupt!");
/*
* CPU count/compare IRQ (unused)
*/
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 9191574d2..1706dc975 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -11,6 +11,8 @@
*
* FIXME: still plenty to do in this file, as much of the code hasn't been
* modified to suit the DECStation's interrupts.
+ *
+ * $Id:$
*/
#include <asm/asm.h>
#include <asm/regdef.h>
@@ -114,12 +116,12 @@ loc_scsi: PANIC("Unimplemented loc_scsi handler")
* Only god knows why... Tell me if you find the reason!
* Andy, 6/16/95
*/
-loc_ethernet: PANIC("Unimplemented loc_ethernet\n")
+loc_ethernet: PANIC("Unimplemented loc_ethernet")
/*
* Keyboard interrupt, remapped to level 1
*/
-loc_keyboard: PANIC("Unimplemented loc_keyboard\n")
+loc_keyboard: PANIC("Unimplemented loc_keyboard")
loc_mouse: PANIC("Unimplemented loc_mouse handler")
@@ -182,7 +184,7 @@ ll_rtc: PANIC("Unimplemented RTC interrupt handler")
* Timer IRQ
* We remap the timer irq to be more similar to a IBM compatible
*/
-ll_timer: PANIC("Timer interrupt!\n");
+ll_timer: PANIC("Timer interrupt!");
/*
* CPU count/compare IRQ (unused)
*/
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index b1892eba6..ae3ba1f9d 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -33,12 +33,13 @@ CONFIG_CPU_R4X00=y
#
CONFIG_ELF_KERNEL=y
CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
-# CONFIG_PARPORT is not set
+# CONFIG_PNP_PARPORT is not set
#
# Loadable module support
@@ -121,6 +122,7 @@ CONFIG_MIPS_JAZZ_SONIC=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
CONFIG_PCNET32=y
@@ -133,7 +135,6 @@ CONFIG_PCNET32=y
# 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_SLIP is not set
@@ -177,6 +178,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
#
# Character devices
@@ -192,6 +194,7 @@ CONFIG_SERIAL=y
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
#
@@ -202,5 +205,6 @@ CONFIG_SERIAL=y
#
# Kernel hacking
#
+# CONFIG_CROSSCOMPILE is not set
# CONFIG_REMOTE_DEBUG is not set
# CONFIG_PROFILE is not set
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 21dd3610b..b3a550177 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -18,6 +18,10 @@ O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \
r2300_misc.o r2300_scall.o r2300_fpu.o r6000_fpu.o unaligned.o
OX_OBJS := mips_ksyms.o
+ifdef CONFIG_MIPS_FPE_MODULE
+M_OBJS += fpe.o
+endif
+
#
# SGI's have very different interrupt/timer hardware.
#
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 00c321a35..c955b964e 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -6,6 +6,8 @@
* for more details.
*
* Copyright (C) 1994, 1995 by Ralf Baechle
+ *
+ * $Id: entry.S,v 1.2 1997/08/11 04:21:31 ralf Exp $
*/
/*
@@ -38,24 +40,17 @@
.set noreorder
.set mips3
.align 4
-/* XXX cli/sti ??? */
handle_bottom_half:
- mfc0 s3,CP0_STATUS # Enable IRQs
- ori t0,s3, 0x1f
- xori t0,0x1e
-
jal do_bottom_half
- mtc0 t0,CP0_STATUS
-
+ nop
b 9f
- mtc0 s3,CP0_STATUS # Restore old IRQ state
+ nop
-reschedule:
- jal schedule
+reschedule: jal schedule
nop
EXPORT(ret_from_sys_call)
- lw t0,bh_mask
+ lw t0,bh_mask
lw t1,bh_active # unused delay slot
and t0,t1
bnez t0,handle_bottom_half
diff --git a/arch/mips/kernel/fpe.c b/arch/mips/kernel/fpe.c
new file mode 100644
index 000000000..46ff43bb4
--- /dev/null
+++ b/arch/mips/kernel/fpe.c
@@ -0,0 +1,55 @@
+/*
+ * The real floating point exception handler. While it doesn't really
+ * make sense to have this in a module, it makes debugging of this code
+ * in the kernel space a lot easier. So far this handler in the released
+ * kernel source is just a dummy.
+ *
+ * Copyright (C) 1997 Ralf Baechle
+ *
+ * $Id:$
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/branch.h>
+#include <asm/ptrace.h>
+
+MODULE_AUTHOR("Ralf Baechle <ralf@gnu.ai.mit.edu>");
+MODULE_DESCRIPTION("Experimental floating point exception handler");
+MODULE_SUPPORTED_DEVICE("MIPS FPU");
+
+static void do_fpe(struct pt_regs *regs, unsigned int fcr31)
+{
+ lock_kernel();
+#ifdef CONF_DEBUG_EXCEPTIONS
+ show_regs(regs);
+#endif
+ printk("Caught floating exception at epc == %08lx, fcr31 == %08x\n",
+ regs->cp0_epc, fcr31);
+ if (compute_return_epc(regs))
+ goto out;
+ force_sig(SIGFPE, current);
+out:
+ unlock_kernel();
+}
+
+/*
+ * For easier experimentation we never increment/decrement
+ * the module useable counter.
+ */
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+
+int init_module(void)
+{
+ return register_fpe(do_fpe);
+}
+
+void cleanup_module(void)
+{
+ unregister_fpe(do_fpe);
+}
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index b2d112373..89ff7a3b0 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -1,17 +1,10 @@
/*
- * linux/arch/mips/kernel/irq.c
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
*
- * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997 Ralf Baechle
*
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- *
- * Mips support by Ralf Baechle and Andreas Busse
- *
- * $Id: irq.c,v 1.2 1997/07/01 08:59:07 ralf Exp $
+ * $Id: irq.c,v 1.4 1997/09/11 20:35:50 ralf Exp $
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -30,13 +23,9 @@
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/jazz.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/vector.h>
-#ifdef CONFIG_SGI
-#include <asm/sgialib.h>
-#endif
unsigned char cache_21 = 0xff;
unsigned char cache_A1 = 0xff;
@@ -51,9 +40,6 @@ unsigned long spurious_count = 0;
static inline void mask_irq(unsigned int irq_nr)
{
unsigned char mask;
-
- if (irq_nr >= 16)
- return;
mask = 1 << (irq_nr & 7);
if (irq_nr < 8) {
@@ -69,9 +55,6 @@ static inline void unmask_irq(unsigned int irq_nr)
{
unsigned char mask;
- if (irq_nr >= 16)
- return;
-
mask = ~(1 << (irq_nr & 7));
if (irq_nr < 8) {
cache_21 &= mask;
@@ -139,13 +122,6 @@ int get_irq_list(char *buf)
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
@@ -255,7 +231,7 @@ int request_irq(unsigned int irq,
int retval;
struct irqaction * action;
- if (irq > 31)
+ if (irq >= 32)
return -EINVAL;
if (!handler)
return -EINVAL;
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index d6657ac89..83712649c 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 1996, 1997 by Ralf Baechle
*
- * $Id: mips_ksyms.c,v 1.2 1997/07/26 19:31:40 ralf Exp $
+ * $Id: mips_ksyms.c,v 1.2 1997/07/29 03:58:54 ralf Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -71,3 +71,19 @@ EXPORT_SYMBOL(port_base);
#ifdef CONFIG_SGI
EXPORT_SYMBOL(hpc3c0);
#endif
+
+/*
+ * Kernel hacking ...
+ */
+#include <asm/branch.h>
+#include <linux/sched.h>
+
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+
+#ifdef CONFIG_MIPS_FPE_MODULE
+EXPORT_SYMBOL(force_sig);
+EXPORT_SYMBOL(__compute_return_epc);
+EXPORT_SYMBOL(register_fpe);
+EXPORT_SYMBOL(unregister_fpe);
+#endif
diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c
index 5e71233af..25ea56fdd 100644
--- a/arch/mips/kernel/pci.c
+++ b/arch/mips/kernel/pci.c
@@ -82,32 +82,6 @@ int pcibios_find_class (unsigned int class_code, unsigned short index,
return PCIBIOS_DEVICE_NOT_FOUND;
}
-const char *pcibios_strerror (int error)
-{
- static char buf[80];
-
- switch (error) {
- case PCIBIOS_SUCCESSFUL:
- return "SUCCESSFUL";
-
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return "FUNC_NOT_SUPPORTED";
-
- case PCIBIOS_BAD_VENDOR_ID:
- return "SUCCESSFUL";
-
- case PCIBIOS_DEVICE_NOT_FOUND:
- return "DEVICE_NOT_FOUND";
-
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return "BAD_REGISTER_NUMBER";
-
- default:
- sprintf (buf, "UNKNOWN RETURN 0x%x", error);
- return buf;
- }
-}
-
/*
* The functions below are machine specific and must be reimplented for
* each PCI chipset configuration. We just run the hook to the machine
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 97a11abc4..b5a5a4428 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -59,12 +59,15 @@ repeat:
goto repeat;
}
page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
+ /* This is a hack for non-kernel-mapped video buffers and similar */
if (MAP_NR(page) >= MAP_NR(high_memory))
return 0;
page += addr & ~PAGE_MASK;
+ /* We can't use flush_page_to_ram() since we're running in
+ * another context ...
+ */
+ flush_cache_all();
retval = *(unsigned long *) page;
- flush_page_to_ram(page);
return retval;
}
@@ -117,14 +120,17 @@ repeat:
handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
-/* this is a hack for non-kernel-mapped video buffers and similar */
- flush_cache_page(vma, addr);
- if (MAP_NR(page) < MAP_NR(high_memory)) {
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ /* This is a hack for non-kernel-mapped video buffers and similar */
+ if (MAP_NR(page) < MAP_NR(high_memory))
+ flush_cache_page(vma, addr);
+ *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ if (MAP_NR(page) < MAP_NR(high_memory))
flush_page_to_ram(page);
- }
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
+ /*
+ * We're bypassing pagetables, so we have to set the dirty bit
+ * ourselves this should also re-instate whatever read-only mode
+ * there was before
+ */
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
flush_tlb_page(vma, addr);
}
@@ -369,7 +375,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case 5:
tmp = child->tss.fpu.hard.control;
break;
- case 6:
+ case 6: /* implementation / version register */
tmp = 0;
break;
default:
diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S
index 0cbc2222f..090b3109f 100644
--- a/arch/mips/kernel/r4k_misc.S
+++ b/arch/mips/kernel/r4k_misc.S
@@ -1,10 +1,12 @@
-/* $Id: r4k_misc.S,v 1.8 1996/07/22 22:32:52 dm Exp $
+/*
* r4k_misc.S: Misc. exception handling code for r4k.
*
* Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
*
* Multi-cpu abstraction and reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4k_misc.S,v 1.2 1997/06/09 06:20:52 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/current.h>
@@ -21,7 +23,7 @@
#include <asm/regdef.h>
#include <asm/stackframe.h>
-#define NOTLB_OPTIMIZE /* If you are paranoid, define this. */
+#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */
/* ABUSE of CPP macros 101. */
@@ -108,10 +110,32 @@
.set noreorder
.set mips3
- /* Note for many R4k variants tlb probes cannot be executed out
+/*
+ * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
+ * 2. A timing hazard exists for the TLBP instruction.
+ *
+ * stalling_instruction
+ * TLBP
+ *
+ * The JTLB is being read for the TLBP throughout the stall generated by the
+ * previous instruction. This is not really correct as the stalling instruction
+ * can modify the address used to access the JTLB. The failure symptom is that
+ * the TLBP instruction will use an address created for the stalling instruction
+ * and not the address held in C0_ENHI and thus report the wrong results.
+ *
+ * The software work-around is to not allow the instruction preceding the TLBP
+ * to stall - make it an NOP or some other instruction guaranteed not to stall.
+ *
+ * Errata 2 will not be fixed. This errata is also on the R5000.
+ *
+ * As if we MIPS hackers wouldn't know how to nop pipelines happy ...
+ */
+#define R5K_HAZARD nop
+
+ /*
+ * Note for many R4k variants tlb probes cannot be executed out
* of the instruction cache else you get bogus results.
*/
-
.align 5
NESTED(r4k_handle_tlbl, PT_SIZE, sp)
.set noat
@@ -120,6 +144,7 @@ invalid_tlbl:
#ifndef NOTLB_OPTIMIZE
/* Test present bit in entry. */
LOAD_PTE(k0, k1)
+ R5K_HAZARD
tlbp
PTE_PRESENT(k0, k1, nopage_tlbl)
PTE_MAKEVALID(k0, k1)
@@ -141,6 +166,7 @@ nopage_tlbl:
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
+ R5K_HAZARD
tlbp # find faulting entry
PTE_WRITABLE(k0, k1, nopage_tlbs)
PTE_MAKEWRITE(k0, k1)
@@ -162,6 +188,7 @@ nopage_tlbs:
.set noat
#ifndef NOTLB_OPTIMIZE
LOAD_PTE(k0, k1)
+ R5K_HAZARD
tlbp # find faulting entry
andi k0, k0, _PAGE_WRITE
beqz k0, nowrite_mod
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 1b00365a6..3ebf269f5 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -4,6 +4,8 @@
* Copyright (C) 1995 Linus Torvalds
* Copyright (C) 1995, 1996 Ralf Baechle
* Copyright (C) 1996 Stoned Elipot
+ *
+ * $Id:$
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -168,9 +170,10 @@ __initfunc(void setup_arch(char **cmdline_p,
break;
#endif
#if defined(CONFIG_MIPS_ARC)
-/* Perhaps arch/mips/deskstation should be renommed arch/mips/arc.
- * For now CONFIG_MIPS_ARC means DeskStation. -Stoned.
- */
+ /*
+ * Perhaps arch/mips/deskstation should be renamed to arch/mips/arc.
+ * For now CONFIG_MIPS_ARC means DeskStation. -Stoned.
+ */
case MACH_GROUP_ARC:
deskstation_setup();
break;
@@ -196,9 +199,6 @@ __initfunc(void setup_arch(char **cmdline_p,
atag = bi_TagFind(tag_drive_info);
memcpy(&drive_info, TAGVALPTR(atag), atag->size);
-#if 0
- aux_device_present = AUX_DEVICE_INFO;
-#endif
memory_end = mips_memory_upper;
/*
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 34ed87fb6..b2e76e8a7 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -4,7 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996 Ralf Baechle
*
- * $Id: signal.c,v 1.3 1997/06/25 20:08:49 ralf Exp $
+ * $Id: signal.c,v 1.4 1997/08/06 19:15:07 miguel Exp $
*/
#include <linux/config.h>
#include <linux/sched.h>
@@ -42,7 +42,7 @@ asmlinkage int sys_sigsuspend(struct pt_regs *regs)
unsigned long mask;
sigset_t *uset, set;
- uset = (sigset_t *)(long) regs->regs[4];
+ uset = (sigset_t *) regs->regs[4];
if (get_user(set, uset))
return -EFAULT;
@@ -392,3 +392,13 @@ asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler)
{
return -ENOSYS;
}
+
+/*
+ * Compatibility syscall. Can be replaced in libc.
+ */
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index f1b117a63..0a190e3ab 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -21,6 +21,7 @@
#include <linux/smp_lock.h>
#include <linux/mman.h>
#include <linux/sched.h>
+#include <linux/utsname.h>
#include <linux/unistd.h>
#include <asm/branch.h>
#include <asm/ptrace.h>
@@ -149,6 +150,43 @@ out:
}
/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ return 0;
+ return -EFAULT;
+}
+
+/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+ int error;
+
+ if (!name)
+ return -EFAULT;
+ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+ error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ error -= __put_user(0,name->release+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ error -= __put_user(0,name->version+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ error = __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = error ? -EFAULT : 0;
+
+ return error;
+}
+
+/*
* Do the indirect syscall syscall.
* Don't care about kernel locking; the actual syscall will do it.
*/
diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
index fd1b39bca..3232af01c 100644
--- a/arch/mips/kernel/syscalls.h
+++ b/arch/mips/kernel/syscalls.h
@@ -7,7 +7,7 @@
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: syscalls.h,v 1.5 1997/07/20 14:57:27 ralf Exp $
+ * $Id: syscalls.h,v 1.6 1997/08/06 19:15:08 miguel Exp $
*/
/*
@@ -35,7 +35,7 @@ SYS(sys_time, 1)
SYS(sys_mknod, 3)
SYS(sys_chmod, 2) /* 4015 */
SYS(sys_chown, 3)
-SYS(sys_break, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_stat, 2)
SYS(sys_lseek, 3)
SYS(sys_getpid, 0) /* 4020 */
@@ -49,11 +49,11 @@ SYS(sys_alarm, 1)
SYS(sys_fstat, 2)
SYS(sys_pause, 0)
SYS(sys_utime, 2) /* 4030 */
-SYS(sys_stty, 0)
-SYS(sys_gtty, 0)
+SYS(sys_ni_syscall, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_access, 2)
SYS(sys_nice, 1)
-SYS(sys_ftime, 0) /* 4035 */
+SYS(sys_ni_syscall, 0) /* 4035 */
SYS(sys_sync, 0)
SYS(sys_kill, 2)
SYS(sys_rename, 2)
@@ -62,7 +62,7 @@ SYS(sys_rmdir, 1) /* 4040 */
SYS(sys_dup, 1)
SYS(sys_pipe, 0)
SYS(sys_times, 1)
-SYS(sys_prof, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_brk, 1) /* 4045 */
SYS(sys_setgid, 1)
SYS(sys_getgid, 0)
@@ -70,13 +70,13 @@ SYS(sys_signal, 2)
SYS(sys_geteuid, 0)
SYS(sys_getegid, 0) /* 4050 */
SYS(sys_acct, 0)
-SYS(sys_phys, 0)
-SYS(sys_lock, 0)
+SYS(sys_ni_syscall, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_ioctl, 3)
SYS(sys_fcntl, 3) /* 4055 */
-SYS(sys_mpx, 2)
+SYS(sys_ni_syscall, 2)
SYS(sys_setpgid, 2)
-SYS(sys_ulimit, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_olduname, 1)
SYS(sys_umask, 1) /* 4060 */
SYS(sys_chroot, 1)
@@ -116,7 +116,7 @@ SYS(sys_fchmod, 2)
SYS(sys_fchown, 3) /* 4095 */
SYS(sys_getpriority, 2)
SYS(sys_setpriority, 3)
-SYS(sys_profil, 0)
+SYS(sys_ni_syscall, 0)
SYS(sys_statfs, 2)
SYS(sys_fstatfs, 2) /* 4100 */
SYS(sys_ioperm, 3)
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index b7ceea080..c38fcf549 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -12,8 +12,6 @@
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
*
- * FIXME: This is the place for a fpu emulator.
- *
* Modified for R3000 by Paul M. Antoine, 1995, 1996
*/
#include <linux/config.h>
@@ -228,8 +226,34 @@ out:
unlock_kernel();
}
+#ifdef CONFIG_MIPS_FPE_MODULE
+static void (*fpe_handler)(struct pt_regs *regs, unsigned int fcr31);
+
+/*
+ * Register_fpe/unregister_fpe are for debugging purposes only. To make
+ * this hack work a bit better there is no error checking.
+ */
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
+{
+ fpe_handler = handler;
+ return 0;
+}
+
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
+{
+ fpe_handler = NULL;
+ return 0;
+}
+#endif
+
void do_fpe(struct pt_regs *regs, unsigned int fcr31)
{
+#ifdef CONFIG_MIPS_FPE_MODULE
+ if (fpe_handler != NULL) {
+ fpe_handler(regs, fcr31);
+ return;
+ }
+#endif
lock_kernel();
#ifdef CONF_DEBUG_EXCEPTIONS
show_regs(regs);
diff --git a/arch/mips/lib/copy_user.S b/arch/mips/lib/copy_user.S
index 30fa6d6e9..a7fdc74e5 100644
--- a/arch/mips/lib/copy_user.S
+++ b/arch/mips/lib/copy_user.S
@@ -1,13 +1,15 @@
/*
- * arch/mips/mips1/memcpy.S
+ * arch/mips/lib/copy_user.S
*
* 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 by Ralf Baechle
+ * Copyright (c) 1996, 1997 by Ralf Baechle
*
- * Less stupid memcpy/user_copy implementation for 32 bit MIPS CPUs.
+ * Less stupid user_copy implementation for 32 bit MIPS CPUs.
+ *
+ * $Id: copy_user.S,v 1.2 1997/08/11 04:26:12 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/regdef.h>
@@ -37,8 +39,8 @@ not_even_the_same_alignment:
andi v1,3
sltu t0,v0,v1
MOVN(v1,v0,t0)
- beqz v1,3f # -> finished
- LONG_ADDU v1,a0 # delay slot
+ beqz v1,src_aligned
+ LONG_ADDU v1,a0
1: lb $1,(a1)
EX(1b, fault)
LONG_ADDIU a1,1
@@ -46,20 +48,22 @@ not_even_the_same_alignment:
EX(2b, fault)
LONG_ADDIU a0,1
bne a0,v1,1b
- LONG_SUBU v0,1 # delay slot
-3:
+ LONG_SUBU v0,1
+src_aligned:
+
/*
* Ok. We've fixed the alignment of the copy src for this case.
* Now let's copy in the usual BLOCK_SIZE byte blocks using unaligned
* stores.
* XXX Align the destination address. This is better if the __copy_user
* encounters an access fault because we never have to deal with an
- * only partially modified destination word.
+ * only partially modified destination word. This is required to
+ * keep the semantics of the result of copy_*_user().
*/
ori v1,v0,BLOCK_SIZE-1
xori v1,BLOCK_SIZE-1
beqz v1,copy_left_over
- nop # delay slot
+ nop
LONG_SUBU v0,v1
LONG_ADDU v1,a0
@@ -81,16 +85,16 @@ not_even_the_same_alignment:
UEX(2b, fault_plus_12)
LONG_ADDIU a0,BLOCK_SIZE
bne a0,v1,1b
- LONG_ADDIU a1,BLOCK_SIZE # delay slot
+ LONG_ADDIU a1,BLOCK_SIZE
9:
b copy_left_over # < BLOCK_SIZE bytes left
- nop # delay slot
+ nop
/* ---------------------------------------------------------------------- */
not_w_aligned:
/*
- * Ok, src or destination are not 8-byte aligned.
+ * Ok, src or destination are not 4-byte aligned.
* Try to fix that. Do at least both addresses have the same alignment?
*/
xor t0,a0,a1
@@ -107,8 +111,8 @@ not_w_aligned:
andi v1,3
sltu t0,v0,v1
MOVN(v1,v0,t0)
- beqz v1,align4 # -> finished
- LONG_ADDU v1,a0 # delay slot
+ beqz v1,__copy_user
+ LONG_ADDU v1,a0
1: lb $1,(a1)
EX(1b, fault)
LONG_ADDIU a1,1
@@ -116,23 +120,23 @@ not_w_aligned:
EX(2b, fault)
LONG_ADDIU a0,1
bne a0,v1,1b
- LONG_SUBU v0,1 # delay slot
+ LONG_SUBU v0,1
b align4
- nop # delay slot
+ nop
/* ---------------------------------------------------------------------- */
LEAF(__copy_user)
or t1,a0,a1
andi t1,3
- bnez t1,not_w_aligned
- move v0,a2 # delay slot
+ bnez t1,not_w_aligned # not word alignment
+ move v0,a2
align4:
ori v1,v0,BLOCK_SIZE-1
xori v1,BLOCK_SIZE-1
beqz v1,copy_left_over
- nop # delay slot
+ nop
LONG_SUBU v0,v1
LONG_ADDU v1,a0
@@ -154,7 +158,7 @@ align4:
EX(2b, fault_plus_12)
LONG_ADDIU a0,BLOCK_SIZE
bne a0,v1,1b
- LONG_ADDIU a1,BLOCK_SIZE # delay slot
+ LONG_ADDIU a1,BLOCK_SIZE
9:
/*
@@ -162,7 +166,7 @@ align4:
*/
copy_left_over:
beqz v0,3f
- nop # delay slot
+ nop
1: lb $1,(a1)
EX(1b, fault)
LONG_ADDIU a1,1
@@ -170,9 +174,11 @@ copy_left_over:
EX(2b, fault)
LONG_SUBU v0,1
bnez v0,1b
- LONG_ADDIU a0,1
-3: jr ra
- nop # delay slot
+ LONG_ADDIU a0,1
+3:
+
+done: jr ra
+ nop
END(__copy_user)
.set at
@@ -193,14 +199,3 @@ fault_plus_8: LONG_ADDIU v0,8
jr ra
fault_plus_12: LONG_ADDIU v0,12
jr ra
-
-/* ---------------------------------------------------------------------- */
-
-/*
- * For now we use __copy_user for __memcpy, too. This is effizient (one
- * instruction penatly) and smaller but adds unwanted error checking we don't
- * need. This hopefully doesn't cover any bugs. The memcpy() wrapper in
- * <asm/string.h> takes care of the return value in a way GCC can optimize.
- */
- .globl __memcpy
-__memcpy = __copy_user
diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c
index 70597201a..c4b4258b7 100644
--- a/arch/mips/mm/loadmmu.c
+++ b/arch/mips/mm/loadmmu.c
@@ -1,7 +1,9 @@
-/* $Id: loadmmu.c,v 1.1.1.1 1997/06/01 03:16:38 ralf Exp $
+/*
* loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: loadmmu.c,v 1.1.1.1 1997/06/01 03:16:38 ralf Exp $
*/
#include <linux/kernel.h>
@@ -76,6 +78,7 @@ void loadmmu(void)
case CPU_R4700:
case CPU_R5000:
case CPU_R5000A:
+ case CPU_NEVADA:
printk("Loading R4000 MMU routines.\n");
ld_mmu_r4xx0();
break;
diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c
index 2b32ca455..2586a961c 100644
--- a/arch/mips/mm/r4xx0.c
+++ b/arch/mips/mm/r4xx0.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r4xx0.c,v 1.5 1997/07/29 22:54:52 tsbogend Exp $
+ * $Id: r4xx0.c,v 1.6 1997/08/06 19:15:10 miguel Exp $
*/
#include <linux/config.h>
@@ -39,7 +39,16 @@ static scache_size, sc_lsize; /* Again, in bytes */
#undef DEBUG_CACHE
/*
- * Zero an entire page.
+ * On processors with QED R4600 style two set assosicative cache
+ * this is the bit which selects the way in the cache for the
+ * indexed cachops.
+ */
+#define waybit 0x2000
+
+/*
+ * Zero an entire page. We have three flavours of the routine available.
+ * One for CPU with 16byte, with 32byte cachelines plus a special version
+ * with nops which handles the buggy R4600 v1.x.
*/
static void r4k_clear_page_d16(unsigned long page)
@@ -1465,11 +1474,8 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma,
*/
page = (KSEG0 + (page & (dcache_size - 1)));
blast_dcache16_page_indexed(page);
- blast_dcache16_page_indexed(page ^ 0x2000);
- if(text) {
+ if(text)
blast_icache16_page_indexed(page);
- blast_icache16_page_indexed(page ^ 0x2000);
- }
}
out:
restore_flags(flags);
@@ -1583,10 +1589,10 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma,
*/
page = (KSEG0 + (page & (dcache_size - 1)));
blast_dcache32_page_indexed(page);
- blast_dcache32_page_indexed(page ^ 0x2000);
+ blast_dcache32_page_indexed(page ^ waybit);
if(text) {
blast_icache32_page_indexed(page);
- blast_icache32_page_indexed(page ^ 0x2000);
+ blast_icache32_page_indexed(page ^ waybit);
}
}
out:
@@ -1776,7 +1782,6 @@ static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
unsigned long flags;
#ifdef DEBUG_CACHE
- /* #if 1 */
printk("r4600_cram[%08lx]", page);
#endif
/*
@@ -1786,7 +1791,6 @@ static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
save_and_cli(flags);
blast_dcache32_page(page);
- blast_dcache32_page(page ^ 0x2000);
#ifdef CONFIG_SGI
{
unsigned long tmp1, tmp2;
@@ -1824,6 +1828,7 @@ static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
static void r4k_flush_cache_sigtramp(unsigned long addr)
{
+ /* XXX protect like uaccess.h loads/stores */
addr &= ~(dc_lsize - 1);
__asm__ __volatile__("nop;nop;nop;nop");
flush_dcache_line(addr);
@@ -2534,7 +2539,7 @@ void ld_mmu_r4xx0(void)
unsigned long cfg = read_32bit_cp0_register(CP0_CONFIG);
int sc_present = 0;
- printk("CPU REVISION IS: %08x\n", read_32bit_cp0_register(CP0_PRID));
+ printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
probe_icache(cfg);
probe_dcache(cfg);
@@ -2546,7 +2551,6 @@ void ld_mmu_r4xx0(void)
case CPU_R4400PC:
case CPU_R4400SC:
case CPU_R4400MC:
-try_again:
probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
sc_present = probe_scache_kseg1(cfg);
break;
@@ -2554,38 +2558,40 @@ try_again:
case CPU_R4600:
case CPU_R4640:
case CPU_R4700:
- case CPU_R5000:
+ case CPU_R5000: /* XXX: We don't handle the true R5000 SCACHE */
+ case CPU_NEVADA:
probe_scache_kseg1 = (probe_func_t)
(KSEG1ADDR(&probe_scache_eeprom));
sc_present = probe_scache_eeprom(cfg);
- /* Try using tags if eeprom give us bogus data. */
- if(sc_present == -1)
- goto try_again;
+ /* Try using tags if eeprom gives us bogus data. */
+ if(sc_present == -1) {
+ probe_scache_kseg1 =
+ (probe_func_t) (KSEG1ADDR(&probe_scache));
+ sc_present = probe_scache_kseg1(cfg);
+ }
break;
};
- if(!sc_present) {
- /* Lacks secondary cache. */
- setup_noscache_funcs();
+ if(sc_present == 1
+ && (mips_cputype == CPU_R4000SC
+ || mips_cputype == CPU_R4000MC
+ || mips_cputype == CPU_R4400SC
+ || mips_cputype == CPU_R4400MC)) {
+ /* Has a true secondary cache. */
+ setup_scache_funcs();
} else {
- /* Has a secondary cache. */
- if(mips_cputype != CPU_R4600 &&
- mips_cputype != CPU_R4640 &&
- mips_cputype != CPU_R4700 &&
- mips_cputype != CPU_R5000) {
- setup_scache_funcs();
- } else {
- setup_noscache_funcs();
- if((mips_cputype != CPU_R5000)) {
- flush_cache_page =
- r4k_flush_cache_page_d32i32_r4600;
- flush_page_to_ram =
- r4k_flush_page_to_ram_d32i32_r4600;
- }
+ /* Lacks true secondary cache. */
+ setup_noscache_funcs();
+ if((mips_cputype != CPU_R5000)) { /* XXX */
+ flush_cache_page =
+ r4k_flush_cache_page_d32i32_r4600;
+ flush_page_to_ram =
+ r4k_flush_page_to_ram_d32i32_r4600;
}
}
+ /* XXX Handle true second level cache w/ split I/D */
flush_cache_sigtramp = r4k_flush_cache_sigtramp;
flush_tlb_all = r4k_flush_tlb_all;
diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c
index 2d23372ae..343a71f9e 100644
--- a/arch/mips/sgi/kernel/indy_int.c
+++ b/arch/mips/sgi/kernel/indy_int.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: indy_int.c,v 1.2 1997/07/01 09:00:58 ralf Exp $
+ * $Id: indy_int.c,v 1.3 1997/08/26 04:34:55 miguel Exp $
*/
#include <linux/config.h>
@@ -260,13 +260,6 @@ int get_irq_list(char *buf)
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
@@ -434,7 +427,7 @@ void indy_local0_irqdispatch(struct pt_regs *regs)
struct irqaction *action;
unsigned char mask = ioc_icontrol->istat0;
unsigned char mask2 = 0;
- int irq;
+ int irq, cpu = smp_processor_id();;
mask &= ioc_icontrol->imask0;
if(mask & ISTAT0_LIO2) {
@@ -446,13 +439,11 @@ void indy_local0_irqdispatch(struct pt_regs *regs)
irq = lc0msk_to_irqnr[mask];
action = local_irq_action[irq];
}
-#if 0
- printk("local0_dispatch: got irq %d mask %2x mask2 %2x\n",
- irq, mask, mask2);
- prom_getchar();
-#endif
+
+ irq_enter(cpu, irq);
kstat.interrupts[irq + 16]++;
action->handler(irq, action->dev_id, regs);
+ irq_exit(cpu, irq);
}
void indy_local1_irqdispatch(struct pt_regs *regs)
@@ -460,7 +451,7 @@ void indy_local1_irqdispatch(struct pt_regs *regs)
struct irqaction *action;
unsigned char mask = ioc_icontrol->istat1;
unsigned char mask2 = 0;
- int irq;
+ int irq, cpu = smp_processor_id();;
mask &= ioc_icontrol->imask1;
if(mask & ISTAT1_LIO3) {
@@ -473,23 +464,24 @@ void indy_local1_irqdispatch(struct pt_regs *regs)
irq = lc1msk_to_irqnr[mask];
action = local_irq_action[irq];
}
-#if 0
- printk("local1_dispatch: got irq %d mask %2x mask2 %2x\n",
- irq, mask, mask2);
- prom_getchar();
-#endif
+ irq_enter(cpu, irq);
kstat.interrupts[irq + 24]++;
action->handler(irq, action->dev_id, regs);
+ irq_exit(cpu, irq);
}
void indy_buserror_irq(struct pt_regs *regs)
{
- kstat.interrupts[6]++;
+ int cpu = smp_processor_id();
+ int irq = 6;
+
+ irq_enter(cpu, irq);
+ kstat.interrupts[irq]++;
printk("Got a bus error IRQ, shouldn't happen yet\n");
show_regs(regs);
printk("Spinning...\n");
- while(1)
- ;
+ while(1);
+ irq_exit(cpu, irq);
}
/* Misc. crap just to keep the kernel linking... */
diff --git a/arch/mips/sgi/kernel/indy_timer.c b/arch/mips/sgi/kernel/indy_timer.c
index 43c1c76c6..d0ba84929 100644
--- a/arch/mips/sgi/kernel/indy_timer.c
+++ b/arch/mips/sgi/kernel/indy_timer.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: indy_timer.c,v 1.2 1997/06/28 23:27:29 ralf Exp $
+ * $Id: indy_timer.c,v 1.2 1997/07/01 09:00:59 ralf Exp $
*/
#include <linux/errno.h>
@@ -101,10 +101,12 @@ static long last_rtc_update = 0;
void indy_timer_interrupt(struct pt_regs *regs)
{
+ int irq = 7;
+
/* Ack timer and compute new compare. */
r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
ack_r4ktimer(r4k_cur);
- kstat.interrupts[7]++;
+ kstat.interrupts[irq]++;
do_timer(regs);
/* We update the Dallas time of day approx. every 11 minutes,
@@ -272,10 +274,15 @@ void indy_timer_init(void)
void indy_8254timer_irq(void)
{
- kstat.interrupts[4]++;
+ int cpu = smp_processor_id();
+ int irq = 4;
+
+ irq_enter(cpu, irq);
+ kstat.interrupts[irq]++;
printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n");
prom_getchar();
prom_imode();
+ irq_exit(cpu, irq);
}
void do_gettimeofday(struct timeval *tv)
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index ac2719977..6c81701d9 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -1,6 +1,3 @@
-#
-# ppc/Makefile
-#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" and "archdep" for cleaning up and making dependencies for
@@ -12,29 +9,28 @@
#
# Copyright (C) 1994 by Linus Torvalds
# Changes for PPC by Gary Thomas
-# Modified by Cort Dougan
+# Rewritten by Cort Dougan and Paul Mackerras
#
+ifeq ($(CONFIG_PMAC),y)
+KERNELBASE =0xc0000000
+else
+KERNELBASE =0x90000000
+endif
+
# PowerPC (cross) tools
-SUFFIX =
-AS = as$(SUFFIX)
-ASFLAGS =
-LD = ld$(SUFFIX)
-LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000
-HOSTCC = gcc
-CC = gcc$(SUFFIX)
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE = ppc-linux-elf-
+else
+CHECKS = checks
+endif
+
+ASFLAGS =
+LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
-CFLAGS = $(CFLAGSINC) \
- -Wstrict-prototypes -fomit-frame-pointer \
- -fno-builtin \
- -finhibit-size-directive \
- -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
-# -fverbose-asm
+CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \
+ -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring
CPP = $(CC) -E $(CFLAGS)
-AR = ar$(SUFFIX)
-RANLIB = ranlib$(SUFFIX)
-STRIP = strip$(SUFFIX)
-NM = nm$(SUFFIX)
ifdef CONFIG_601
CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
@@ -55,59 +51,35 @@ SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc/xmon
+CORE_FILES += arch/ppc/xmon/x.o
+endif
+
+ifdef CONFIG_PMAC
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
+else
+# PReP and CHRP systems
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+endif
checks:
@$(MAKE) -C arch/$(ARCH)/kernel checks
-netboot: checks vmlinux
- @$(MAKEBOOT) netboot
-
-znetboot: checks vmlinux
- @$(MAKEBOOT) znetboot
+BOOT_TARGETS = netboot znetboot zImage floppy install \
+ vmlinux.coff znetboot.initrd zImage.initrd
-#rcpboot: checks vmlinux
-# @$(MAKEBOOT) rcpboot
+$(BOOT_TARGETS): $(CHECKS) vmlinux
+ @$(MAKEBOOT) $@
-zImage: checks vmlinux
- @$(MAKEBOOT) zImage
-
-floppy: checks vmlinux
- @$(MAKEBOOT) floppy
-
-install: checks vmlinux
- @$(MAKEBOOT) install
-
-vmlinux.coff : checks vmlinux
- $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
-
-arch/ppc/kernel: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
-
-arch/ppc/mm: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/mm
-
-arch/ppc/lib: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
-
-diffs:
- arch/ppc/mkdiff
-
-tar:
- arch/ppc/mktar
+tags:
+ etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
archclean:
- rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
- rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
- rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+ rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
+ rm -f arch/ppc/kernel/checks
@$(MAKEBOOT) clean
archdep:
- $(MAKE) -C arch/ppc/boot fastdep
- $(MAKE) -C arch/ppc/kernel fastdep
- $(MAKE) -C arch/ppc/mm fastdep
- $(MAKE) -C arch/ppc/lib fastdep
-
-tags :
- etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c
+ $(MAKEBOOT) fastdep
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 5dcac750e..a731ec2a0 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -22,58 +22,81 @@
$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
-ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
GZIP_FLAGS = -v9
SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
-
+OBJECTS := head.o inflate.o unzip.o misc.o vreset.o kbd.o
CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
all: $(TOPDIR)/zImage
mkprep : mkprep.c
$(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+piggyback : piggyback.c
+ $(HOSTCC) $(CFLAGSINC) -o piggyback piggyback.c
+
find_name : find_name.c
$(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
-mk_type41: mk_type41.c
- $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
-
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
floppy: $(TOPDIR)/vmlinux zImage
dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
-netboot : $(TOPDIR)/vmlinux mkprep
- mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+floppy.initrd: $(TOPDIR)/vmlinux zImage
+ dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b
+
+znetboot : zImage mkprep
+ cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux
-znetboot : zvmlinux mkprep
- mkprep zvmlinux $(TOPDIR)/znetboot
- cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
+znetboot.initrd : zImage.initrd mkprep
+ cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux
-rcpboot : znetboot
- rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+#
+# This really needs to go away. Perhaps a
+# zImage.prep and zImage.chrp might be better.
+# Once we're able to get a lilo-ish program
+# on prep systems this won't be a problem.
+# -- Cort
+#
+ifdef CONFIG_CHRP
+zImage: zvmlinux
+ cp zvmlinux $(TOPDIR)/zImage
+zImage.initrd: zvmlinux.initrd
+ cp zvmlinux.initrd $(TOPDIR)/zImage.initrd
+
+zvmlinux: $(OBJECTS) $(SYSTEM) find_name vmlinux.gz piggyback
+ ./piggyback < vmlinux.gz | $(AS) -o piggy.o
+ $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) piggy.o
+ rm -f piggy.o
+else
zImage: zvmlinux mkprep
mkprep -pbp zvmlinux $(TOPDIR)/zImage
-install: zImage
- dd if=$(TOPDIR)/zImage of=/dev/sda4
- ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
- cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+zImage.initrd: zvmlinux.initrd mkprep
+ mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd
-zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name
- mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
- $(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
- rm -f piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name vmlinux.gz
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+ zvmlinux.tmp $@
+ rm zvmlinux.tmp
+endif
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+ dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz
+
+zvmlinux.initrd: zvmlinux
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ zvmlinux $@
clean:
- rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
- rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+ rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name
+ rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*}
fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff --git a/arch/ppc/boot/find_name.c b/arch/ppc/boot/find_name.c
new file mode 100644
index 000000000..23646fb69
--- /dev/null
+++ b/arch/ppc/boot/find_name.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors. -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+ unsigned long addr, cmp, i;
+ FILE *f;
+ char *ptr;
+ char s[256], last[256];
+
+ if ( argc < 2 )
+ {
+ fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+ exit(-1);
+ }
+
+ for ( i = 1 ; argv[i] ; i++ )
+ {
+ sscanf( argv[i], "%0x", &addr );
+ /* adjust if addr is relative to kernelbase */
+ if ( addr < PAGE_OFFSET )
+ addr += PAGE_OFFSET;
+
+ if ( (f = fopen( "System.map", "r" )) == NULL )
+ {
+ perror("fopen()\n");
+ exit(-1);
+ }
+
+ while ( !feof(f) )
+ {
+ fgets(s, 255 , f);
+ sscanf( s, "%0x", &cmp );
+ if ( addr < cmp )
+ break;
+ strcpy( last, s);
+ }
+
+ printf( "%s", last);
+ }
+ fclose(f);
+}
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
index 6b25cb157..2cfda5cbe 100644
--- a/arch/ppc/boot/head.S
+++ b/arch/ppc/boot/head.S
@@ -13,17 +13,6 @@
start:
bl start_
start_:
-/* TEMP - No residual data on BeBox (yet) */
-#if 0
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r2,IS_BE_BOX>>16
- ori r2,r2,IS_BE_BOX&0xFFFF
- cmp 0,r30,r2
- bne notBeBox
- li r3,0
-#endif
-notBeBox:
-/* TEMP */
mr r11,r3 /* Save pointer to residual data */
mfmsr r3 /* Turn off interrupts */
li r4,0
@@ -48,7 +37,9 @@ notBeBox:
mtlr r21
mtctr r22
bctr /* Jump to code */
-/* Relocate code to final resting spot */
+/*
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
relocate:
mflr r3 /* Compute code bias */
subi r3,r3,4
@@ -98,13 +89,26 @@ start_ldr:
mr r5,r6 /* Checksum */
mr r6,r11 /* Residual data */
bl decompress_kernel
- /*mr r29,r3*/ /* R3 = TotalMemory */
- /*lis r28,hold_residual@h
- ori r28,r28,hold_residual@l*/
+
/* changed to use r3 (as firmware does) for kernel
as ptr to residual -- Cort*/
- li r5,0x100 /* Kernel code starts here */
- mtlr r5
+ lis r6,cmd_line@h
+ ori r6,r6,cmd_line@l
+ subi r7,r6,1
+00: lbzu r2,1(r7)
+ cmpi 0,r2,0
+ bne 00b
+
+ /* r4,r5 have initrd_start, size */
+ lis r2,initrd_start@h
+ ori r2,r2,initrd_start@l
+ lwz r4,0(r2)
+ lis r2,initrd_end@h
+ ori r2,r2,initrd_end@l
+ lwz r5,0(r2)
+
+ li r9,0x00c /* Kernel code starts here */
+ mtlr r9
blr
hang:
b hang
@@ -142,6 +146,45 @@ _put_HID0:
blr
/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+ .globl udelay
+udelay:
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,1 /* 601 ? */
+ bne .udelay_not_601
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+.udelay_not_601:
+ mulli r4,r3,1000 /* nanoseconds */
+ addi r4,r4,59
+ li r5,60
+ divw r4,r4,r5 /* BUS ticks */
+1: mftbu r5
+ mftb r6
+ mftbu r7
+ cmp 0,r5,r7
+ bne 1b /* Get [synced] base time */
+ addc r9,r6,r4 /* Compute end time */
+ addze r8,r5
+2: mftbu r5
+ cmp 0,r5,r8
+ blt 2b
+ bgt 3f
+ mftb r6
+ cmp 0,r6,r9
+ blt 2b
+3: blr
+
+/*
* This space [buffer] is used to forceably flush the data cache when
* running in copyback mode. This is necessary IFF the data cache could
* contain instructions for which the instruction cache has stale data.
diff --git a/arch/ppc/boot/kbd.c b/arch/ppc/boot/kbd.c
new file mode 100644
index 000000000..6c0065b00
--- /dev/null
+++ b/arch/ppc/boot/kbd.c
@@ -0,0 +1,166 @@
+/* Keyboard handler */
+
+#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */
+
+#define L 0x0001 /* locking function */
+#define SHF 0x0002 /* keyboard shift */
+#define ALT 0x0004 /* alternate shift -- alternate chars */
+#define NUM 0x0008 /* numeric shift cursors vs. numeric */
+#define CTL 0x0010 /* control shift -- allows ctl function */
+#define CPS 0x0020 /* caps shift -- swaps case of letter */
+#define ASCII 0x0040 /* ascii code for this key */
+#define STP 0x0080 /* stop output */
+#define FUNC 0x0100 /* function key */
+#define SCROLL 0x0200 /* scroll lock key */
+
+unsigned char shfts, ctls, alts, caps, num, stp;
+
+#define KBDATAP 0x60 /* kbd data port */
+#define KBSTATUSPORT 0x61 /* kbd status */
+#define KBSTATP 0x64 /* kbd status port */
+#define KBINRDY 0x01
+#define KBOUTRDY 0x02
+
+#define _x__ 0x00 /* Unknown / unmapped */
+
+const unsigned short action[] = {
+ 0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */
+ ASCII, ASCII, SHF, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */
+ ALT, ASCII, CPS, FUNC, FUNC, FUNC, FUNC, FUNC, /* scan 56-63 */
+ FUNC, FUNC, FUNC, FUNC, FUNC, NUM,SCROLL, ASCII, /* scan 64-71 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */
+ ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */
+ 0,0,0,0,0,0,0,0, /* scan 88-95 */
+ 0,0,0,0,0,0,0,0, /* scan 96-103 */
+ 0,0,0,0,0,0,0,0, /* scan 104-111 */
+ 0,0,0,0,0,0,0,0, /* scan 112-119 */
+ 0,0,0,0,0,0,0,0, /* scan 120-127 */
+};
+
+static int
+kbd(noblock)
+ int noblock;
+{
+ unsigned char dt, brk, act;
+ int first = 1;
+loop:
+ if (noblock) {
+ if ((inb(KBSTATP) & KBINRDY) == 0)
+ return (-1);
+ } else while((inb(KBSTATP) & KBINRDY) == 0) ;
+
+ dt = inb(KBDATAP);
+
+ brk = dt & 0x80; /* brk == 1 on key release */
+ dt = dt & 0x7f; /* keycode */
+
+ act = action[dt];
+ if (/*act&SHF*/ dt == 54)
+ shfts = brk ? 0 : 1;
+ if (/*act&ALT*/ dt == 48)
+ alts = brk ? 0 : 1;
+ if (/*act&NUM*/ dt == 69)
+ if (act&L) {
+ /* NUM lock */
+ if(!brk)
+ num = !num;
+ } else
+ num = brk ? 0 : 1;
+ if (/*act&CTL*/ dt == 29)
+ ctls = brk ? 0 : 1;
+ if (/*act&CPS*/ dt == 58)
+ if (act&L) {
+ /* CAPS lock */
+ if(!brk)
+ caps = !caps;
+ } else
+ caps = brk ? 0 : 1;
+ if (0/*act&STP*/)
+ if (act&L) {
+ if(!brk)
+ stp = !stp;
+ } else
+ stp = brk ? 0 : 1;
+
+ if ((act&ASCII) && !brk) {
+ unsigned char chr;
+ if (shfts)
+ chr = shift_map[dt];
+ else if (ctls)
+ chr = ctrl_map[dt];
+ else
+ chr = plain_map[dt];
+ if (alts)
+ chr |= 0x80;
+
+ if (caps && (chr >= 'a' && chr <= 'z'))
+ chr -= 'a' - 'A' ;
+ if ( chr == 0x01 ) chr = '\n'; /* hack */
+#define CTRL(s) (s & 0x1F)
+ if ((chr == '\r') || (chr == '\n') || (chr == CTRL('A')) || (chr == CTRL('S')))
+ {
+ /* Wait for key up */
+ while (1)
+ {
+ while((inb(KBSTATP) & KBINRDY) == 0) ;
+ dt = inb(KBDATAP);
+ if (dt & 0x80) /* key up */ break;
+ }
+ }
+ return (chr);
+ }
+ if (first && brk) return (0); /* Ignore initial 'key up' codes */
+ goto loop;
+}
+
+static
+scankbd(void) {
+ return (kbd(1) != -1);
+}
+
+static
+kbdreset(void)
+{
+ unsigned char c;
+ int i;
+
+ /* Send self-test */
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0xAA);
+ while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */
+ if ((c = inb(KBDATAP)) != 0x55)
+ {
+ puts("Keyboard self test failed - result:");
+ puthex(c);
+ puts("\n");
+ }
+ /* Enable interrupts and keyboard controller */
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0x60);
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBDATAP,0x45);
+ for (i = 0; i < 10000; i++) udelay(1);
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0xAE);
+}
+
+static int kbd_reset = 0;
+
+CRT_getc(void)
+{
+ int c;
+ if (!kbd_reset) {kbdreset(); kbd_reset++; }
+ while ((c = kbd(0)) == 0) ;
+ return(c);
+}
+
+CRT_tstc(void)
+{
+ if (!kbd_reset) {kbdreset(); kbd_reset++; }
+ return ((inb(KBSTATP) & KBINRDY) != 0);
+}
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index a983ea106..4d2a723f5 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -8,13 +8,23 @@
* puts by Nick Holloway 1993
*
* Adapted for PowerPC by Gary Thomas
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
*/
#include "gzip.h"
#include "lzw.h"
#include "asm/residual.h"
+#include <elf.h>
RESIDUAL hold_residual;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+extern char input_data[];
+extern int input_len;
+void cksum_text(void);
+void verify_data(unsigned long load_addr);
+
void dump_buf(unsigned char *p, int s);
#define EOF -1
@@ -26,8 +36,7 @@ unsigned outcnt;
unsigned insize;
unsigned inptr;
-extern char input_data[];
-extern int input_len;
+char cmd_line[256];
int input_ptr;
@@ -56,6 +65,9 @@ int lines, cols;
int orig_x, orig_y;
void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
void *malloc(int size)
{
@@ -77,7 +89,7 @@ void *malloc(int size)
*/
if (free_mem_ptr < (long)&end) {
- if (free_mem_ptr > (long)&input_data[input_ptr])
+ if (free_mem_ptr > (long)&zimage_start[input_ptr])
error("\nOut of memory\n");
return p;
@@ -87,7 +99,7 @@ void *malloc(int size)
#endif
return p;
puts("large kernel, low 1M tight...");
- free_mem_ptr = (long)input_data;
+ free_mem_ptr = (long)zimage_start;
}
}
@@ -115,6 +127,53 @@ static void scroll()
vidmem[i] = ' ';
}
+tstc(void)
+{
+ return (CRT_tstc() );
+}
+
+getc(void)
+{
+ while (1) {
+ if (CRT_tstc()) return (CRT_getc());
+ }
+}
+
+void
+putc(const char c)
+{
+ int x,y;
+
+ x = orig_x;
+ y = orig_y;
+
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ } else if (c == '\b') {
+ if (x > 0) {
+ x--;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ }
+ }
+
+ cursor(x, y);
+
+ orig_x = x;
+ orig_y = y;
+}
+
void puts(const char *s)
{
int x,y;
@@ -229,10 +288,10 @@ puts("*");
insize = 0;
do {
len = INBUFSIZ-insize;
- if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+ if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1;
if (len == 0 || len == EOF) break;
- for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+ for (i=0;i<len;i++) inbuf[insize+i] = zimage_start[input_ptr+i];
insize += len;
input_ptr += len;
} while (insize < INBUFSIZ);
@@ -313,7 +372,15 @@ void error(char *x)
unsigned long
decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
{
- unsigned long TotalMemory;
+ int timer;
+ char *cp, ch;
+ Elf32_Ehdr *eh;
+ Elf32_Shdr *sh, *strtab_shdr;
+ char *strtab;
+ unsigned long i;
+ extern unsigned long start(void);
+
+
output_data = (char *)0x0; /* Points to 0 */
lines = 25;
cols = 80;
@@ -339,33 +406,135 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
clear_bufs();
makecrc();
- puts("Loaded at "); puthex(load_addr); puts(", "); puthex(num_words); puts(" words");
- puts(", cksum = "); puthex(cksum); puts("\n");
+ puts("Cksum: "); puthex(cksum); puts("\n");
+ puts("Loaded at: "); puthex(load_addr); puts(" "); puthex(num_words+load_addr);
+ puts("\n");
+ puts("Boot code relocated to: "); puthex((unsigned long)start); puts(" ");
+ puthex((unsigned long)(num_words+start));
+ puts("\n");
if (residual) {
- _bcopy(residual, &hold_residual, sizeof(hold_residual));
- puts("Residual data at "); puthex(residual); puts("\n");
- show_residual_data(residual);
- TotalMemory = residual->TotalMemory;
- } else {
- TotalMemory = 0x01000000;
+ _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual));
+ puts("Residual data at: "); puthex((unsigned long)residual); puts(" ");
+ puthex((unsigned long)((unsigned long)(residual->ResidualLength) + residual)); puts("\n");
+ puts("Residual data relocated to: "); puthex((unsigned long)&hold_residual); puts("\n");
}
- puts("Uncompressing Linux...");
+ /*
+ * Take care of initrd if we have one
+ */
+ /*
+ * the _actual_ load addr is 64k (elf hdr size) lower but the
+ * firmware gives us the starting exec point not the load ptr
+ * -- Cort
+ */
+ eh = (Elf32_Ehdr *)(load_addr - 65536);
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/
+
+ /* find string table */
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ /*puts("Section: "); puthex(i);
+ puts(" type: "); puthex(sh->sh_type);
+ puts(" offset: "); puthex(sh->sh_offset);
+ puts("\n");*/
+
+ if ( sh->sh_type == SHT_STRTAB )
+ {
+ strtab_shdr = sh;
+ strtab = (char *)(sh->sh_offset + (unsigned long)eh);
+ /*puts("Found strtab at: "); puthex((unsigned long)strtab);
+ puts("\n");*/
+ break;
+ }
+ }
- method = get_method(0);
+ /* find the initrd and image sections */
+ if ( strtab_shdr )
+ {
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) )
+ {
+ initrd_start = (unsigned long)eh + sh->sh_offset;
+ initrd_end = initrd_start + sh->sh_size;
+ puts("Found initrd at: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end);
+ puts("\n");
+ }
+ if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) )
+ {
+ zimage_start = (char *)((unsigned long)eh + sh->sh_offset);
+ zimage_size = sh->sh_size;
+ puts("Found zimage at: "); puthex((unsigned long)zimage_start);
+ puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+ puts("\n");
+ }
+ }
+ }
+ else
+ {
+ puts("Couldn't find string table for boot image!\n");
+ }
+
+ /* relocate initrd */
+ if ( initrd_start )
+ {
+ memcpy ((void *)0x00D00000,(void *)initrd_start,
+ initrd_end - initrd_start );
+ initrd_end = 0x00D00000 + initrd_end - initrd_start;
+ initrd_start = 0x00D00000;
+ puts("Moved initrd to: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end); puts("\n");
+ }
- work(0, 0);
+ CRT_tstc(); /* Forces keyboard to be initialized */
+ puts("\nLinux/PPC load: ");
+ timer = 0;
+ cp = cmd_line;
+ while (timer++ < 5*1000) {
+ if (tstc()) {
+ while ((ch = getc()) != '\n' && ch != '\r') {
+ if (ch == '\b') {
+ if (cp != cmd_line) {
+ cp--;
+ puts("\b \b");
+ }
+ } else {
+ *cp++ = ch;
+ putc(ch);
+ }
+ }
+ break; /* Exit 'timer' loop */
+ }
+ udelay(1000); /* 1 msec */
+ }
+ *cp = 0;
+ puts("\n");
+
+ /* mappings on early boot can only handle 16M */
+ if ( (int)(&cmd_line[0]) > (16<<20))
+ puts("cmd_line > 16M\n");
+ if ( (int)&hold_residual > (16<<20))
+ puts("hold_residual > 16M\n");
+ if ( initrd_start > (16<<20))
+ puts("initrd_start > 16M\n");
+
+
+ puts("Uncompressing Linux...");
+ method = get_method(0);
+ work(0, 0);
puts("done.\n");
+
puts("Now booting the kernel\n");
- /*return (TotalMemory);*/ /* Later this can be a pointer to saved residual data */
- return &hold_residual;
+ return (unsigned long)&hold_residual;
}
show_residual_data(RESIDUAL *res)
{
puts("Residual data: "); puthex(res->ResidualLength); puts(" bytes\n");
- puts("Total memory: "); puthex(res->TotalMemory); puts("\n");
#if 0
puts("Residual structure = "); puthex(sizeof(*res)); puts(" bytes\n");
dump_buf(&hold_residual, 32);
@@ -407,14 +576,14 @@ cksum_data()
{
unsigned int *ptr, len, cksum, cnt;
cksum = cnt = 0;
- ptr = input_data;
+ ptr = (unsigned int *)zimage_start;
puts("Checksums: ");
- for (len = 0; len < input_len; len += 4) {
+ for (len = 0; len < zimage_size; len += 4) {
cksum ^= *ptr++;
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
@@ -429,7 +598,7 @@ cksum_data()
puts("Data cksum = "); puthex(cksum); puts("\n");
}
-cksum_text()
+void cksum_text(void)
{
extern int start, etext;
unsigned int *ptr, len, text_len, cksum, cnt;
@@ -442,7 +611,7 @@ cksum_text()
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
@@ -457,24 +626,24 @@ cksum_text()
puts("TEXT cksum = "); puthex(cksum); puts("\n");
}
-verify_data(unsigned long load_addr)
+void verify_data(unsigned long load_addr)
{
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
}
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
- dump_buf(copy_ptr-1, 128);
- dump_buf(orig_ptr-1, 128);
+ dump_buf((unsigned char *) (copy_ptr-1), 128);
+ dump_buf((unsigned char *) (orig_ptr-1), 128);
puts("Total errors = "); puthex(errors*4); puts("\n");
while (1) ;
}
@@ -486,9 +655,9 @@ test_data(unsigned long load_addr)
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
@@ -532,7 +701,7 @@ void dump_buf(unsigned char *p, int s)
}
while (s > 0)
{
- puthex(p); puts(": ");
+ puthex((unsigned long)p); puts(": ");
for (i = 0; i < 16; i++)
{
if (i < s)
diff --git a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c
index 417334670..06b08df98 100644
--- a/arch/ppc/boot/mkprep.c
+++ b/arch/ppc/boot/mkprep.c
@@ -131,17 +131,18 @@ int main(int argc, char *argv[])
argptr++;
/* skip elf header in input file */
- lseek(in_fd, elfhdr_size, SEEK_SET);
+ if ( !prep )
+ lseek(in_fd, elfhdr_size, SEEK_SET);
/* write prep partition if necessary */
if ( prep )
- write_prep_partition( in_fd, out_fd );
+ write_prep_partition( in_fd, out_fd );
/* write input image to bootimage */
if ( asmoutput )
- write_asm_data( in_fd, out_fd );
+ write_asm_data( in_fd, out_fd );
else
- copy_image(in_fd, out_fd);
+ copy_image(in_fd, out_fd);
return 0;
}
@@ -161,28 +162,11 @@ void write_prep_partition(int in, int out)
}
bzero( block, sizeof block );
-
- /* set entry point and boot image size */
- *entry = cpu_to_le32(0x400);
- /* need use size - elfheader? */
+ /* set entry point and boot image size skipping over elf header */
+ *entry = cpu_to_le32(0x400+65536);
*length = cpu_to_le32(info.st_size+0x400);
- /*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block. It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition. The "PReP" partition contains the "load image" starting
- * at offset zero within the partition. The first block of the load image is
- * a dummy PC boot block. The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image. The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-
/* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
@@ -220,7 +204,7 @@ void write_prep_partition(int in, int out)
/* This has to be 0 on the PowerStack? */
pe->beginning_sector = cpu_to_le32(0);
#endif
-/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+ pe->number_of_sectors = cpu_to_le32(2*18*80-1);
write( out, block, sizeof(block) );
write( out, entry, sizeof(*entry) );
diff --git a/arch/ppc/coffboot/.cvsignore b/arch/ppc/coffboot/.cvsignore
new file mode 100644
index 000000000..45968cd8d
--- /dev/null
+++ b/arch/ppc/coffboot/.cvsignore
@@ -0,0 +1,7 @@
+.depend
+vmlinux.coff.initrd
+coffboot
+elfextract
+hack-coff
+vmlinux.coff
+zImage
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
new file mode 100644
index 000000000..e145411c6
--- /dev/null
+++ b/arch/ppc/coffboot/Makefile
@@ -0,0 +1,50 @@
+# Makefile for making XCOFF bootable images for booting on PowerMacs
+# using Open Firmware.
+#
+# Paul Mackerras January 1997
+
+# PowerPC (cross) tools
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE =powerpc-eabi-
+endif
+
+HOSTCC = gcc
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
+ --add-section=image=zImage
+LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+GZIP = gzip -9
+
+OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+LIBS = $(TOPDIR)/lib/lib.a
+
+vmlinux.coff: coffboot hack-coff zImage
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+ ./hack-coff $@
+
+vmlinux.coff.initrd: coffboot hack-coff zImage ramdisk.image.gz
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ coffboot $@
+ ./hack-coff $@
+
+coffboot: $(OBJS) ld.script
+ $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: $(TOPDIR)/vmlinux elfextract
+ ./elfextract $(TOPDIR)/vmlinux | $(GZIP) >zImage
+
+hack-coff: hack-coff.c
+ $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+
+elfextract: elfextract.c
+ $(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c
+
+clean:
+ rm -f elfextract hack-coff coffboot zImage vmlinux.coff
+
+fastdep:
diff --git a/arch/ppc/coffboot/crt0.S b/arch/ppc/coffboot/crt0.S
new file mode 100644
index 000000000..43ae4e0ec
--- /dev/null
+++ b/arch/ppc/coffboot/crt0.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+ .text
+ .globl _start
+_start:
+ .long __start,0,0
+
+ .globl __start
+__start:
+ lis 9,_start@h
+ lis 8,_etext@ha
+ addi 8,8,_etext@l
+1: dcbf 0,9
+ icbi 0,9
+ addi 9,9,0x20
+ cmplwi 0,9,8
+ blt 1b
+ b start
diff --git a/arch/ppc/coffboot/elfextract.c b/arch/ppc/coffboot/elfextract.c
new file mode 100644
index 000000000..1b50ca475
--- /dev/null
+++ b/arch/ppc/coffboot/elfextract.c
@@ -0,0 +1,98 @@
+/*
+ * Extract the loadable program segment from an elf file.
+ *
+ * Copyright 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdio.h>
+#include <linux/elf.h>
+
+FILE *fi, *fo;
+char *ni, *no;
+char buf[65536];
+
+void
+rd(void *buf, int len)
+{
+ int nr;
+
+ nr = fread(buf, 1, len, fi);
+ if (nr == len)
+ return;
+ if (ferror(fi))
+ fprintf(stderr, "%s: read error\n", ni);
+ else
+ fprintf(stderr, "%s: short file\n", ni);
+ exit(1);
+}
+
+main(int ac, char **av)
+{
+ unsigned nb, len;
+ Elf32_Ehdr eh;
+ Elf32_Phdr ph;
+
+ if (ac > 3 || ac > 1 && av[1][0] == '-') {
+ fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
+ exit(0);
+ }
+
+ fi = stdin;
+ ni = "(stdin)";
+ fo = stdout;
+ no = "(stdout)";
+
+ if (ac > 1) {
+ ni = av[1];
+ fi = fopen(ni, "rb");
+ if (fi == NULL) {
+ perror(ni);
+ exit(1);
+ }
+ }
+
+ rd(&eh, sizeof(eh));
+ if (eh.e_ident[EI_MAG0] != ELFMAG0
+ || eh.e_ident[EI_MAG1] != ELFMAG1
+ || eh.e_ident[EI_MAG2] != ELFMAG2
+ || eh.e_ident[EI_MAG3] != ELFMAG3) {
+ fprintf(stderr, "%s: not an ELF file\n", ni);
+ exit(1);
+ }
+
+ fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0);
+ rd(&ph, sizeof(ph));
+ if (ph.p_type != PT_LOAD) {
+ fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
+ exit(1);
+ }
+
+ if (ac > 2) {
+ no = av[2];
+ fo = fopen(no, "wb");
+ if (fo == NULL) {
+ perror(no);
+ exit(1);
+ }
+ }
+
+ fseek(fi, ph.p_offset, 0);
+ for (len = ph.p_filesz; len != 0; len -= nb) {
+ nb = len;
+ if (nb > sizeof(buf))
+ nb = sizeof(buf);
+ rd(buf, nb);
+ if (fwrite(buf, 1, nb, fo) != nb) {
+ fprintf(stderr, "%s: write error\n", no);
+ exit(1);
+ }
+ }
+
+ fclose(fo);
+ fclose(fi);
+ exit(0);
+}
diff --git a/arch/ppc/coffboot/hack-coff.c b/arch/ppc/coffboot/hack-coff.c
new file mode 100644
index 000000000..3dfa8d800
--- /dev/null
+++ b/arch/ppc/coffboot/hack-coff.c
@@ -0,0 +1,79 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdio.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC 0x010b
+
+#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \
+ + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+ ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \
+ + (((unsigned char *)(x))[1] << 16) \
+ + (((unsigned char *)(x))[2] << 8) \
+ + ((unsigned char *)(x))[3])
+
+main(int ac, char **av)
+{
+ int fd;
+ int i, nsect;
+ int aoutsz;
+ struct external_filehdr fhdr;
+ AOUTHDR aout;
+ struct external_scnhdr shdr;
+
+ if (ac != 2) {
+ fprintf(stderr, "Usage: hack-coff coff-file\n");
+ exit(1);
+ }
+ if ((fd = open(av[1], 2)) == -1) {
+ perror(av[2]);
+ exit(1);
+ }
+ if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+ goto readerr;
+ i = get_16be(fhdr.f_magic);
+ if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+ fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+ exit(1);
+ }
+ aoutsz = get_16be(fhdr.f_opthdr);
+ if (read(fd, &aout, aoutsz) != aoutsz)
+ goto readerr;
+ nsect = get_16be(fhdr.f_nscns);
+ for (i = 0; i < nsect; ++i) {
+ if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+ goto readerr;
+ if (strcmp(shdr.s_name, ".text") == 0) {
+ put_16be(aout.o_snentry, i+1);
+ put_16be(aout.o_sntext, i+1);
+ } else if (strcmp(shdr.s_name, ".data") == 0) {
+ put_16be(aout.o_sndata, i+1);
+ } else if (strcmp(shdr.s_name, ".bss") == 0) {
+ put_16be(aout.o_snbss, i+1);
+ }
+ }
+ put_16be(aout.magic, AOUT_MAGIC);
+ if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+ || write(fd, &aout, aoutsz) != aoutsz) {
+ fprintf(stderr, "%s: write error\n", av[1]);
+ exit(1);
+ }
+ close(fd);
+ exit(0);
+
+readerr:
+ fprintf(stderr, "%s: read error or file too short\n", av[1]);
+ exit(1);
+}
diff --git a/arch/ppc/coffboot/ld.script b/arch/ppc/coffboot/ld.script
new file mode 100644
index 000000000..2469ed65d
--- /dev/null
+++ b/arch/ppc/coffboot/ld.script
@@ -0,0 +1,68 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ *(.got1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ _etext = .;
+ PROVIDE (etext = .);
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
diff --git a/arch/ppc/coffboot/main.c b/arch/ppc/coffboot/main.c
new file mode 100644
index 000000000..ab0ee6c4a
--- /dev/null
+++ b/arch/ppc/coffboot/main.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "rs6000.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0xc0000000
+#define RAM_END 0xc0800000 /* only 8M mapped with BATs */
+
+#define RAM_FREE 0xc0540000 /* after image of coffboot */
+
+char *avail_ram;
+char *end_avail;
+
+coffboot(int a1, int a2, void *prom)
+{
+ void *options;
+ unsigned loadbase;
+ struct external_filehdr *eh;
+ struct external_scnhdr *sp;
+ struct external_scnhdr *isect, *rsect;
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ printf("coffboot starting\n");
+ options = finddevice("/options");
+ if (options == (void *) -1)
+ exit();
+ if (getprop(options, "load-base", &loadbase, sizeof(loadbase))
+ != sizeof(loadbase)) {
+ printf("error getting load-base\n");
+ exit();
+ }
+ setup_bats();
+
+ eh = (struct external_filehdr *) loadbase;
+ ns = get_16be(eh->f_nscns);
+ oh = get_16be(eh->f_opthdr);
+
+ sp = (struct external_scnhdr *) (loadbase + sizeof(struct external_filehdr) + oh);
+ isect = rsect = NULL;
+ for (i = 0; i < ns; ++i, ++sp) {
+ if (strcmp(sp->s_name, "image") == 0)
+ isect = sp;
+ else if (strcmp(sp->s_name, "initrd") == 0)
+ rsect = sp;
+ }
+ if (isect == NULL) {
+ printf("image section not found\n");
+ exit();
+ }
+
+ if (rsect != NULL && (initrd_size = get_32be(rsect->s_size)) != 0) {
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ printf("initial ramdisk at %x (%u bytes)\n",
+ initrd_start, initrd_size);
+ memcpy((char *) initrd_start,
+ (char *) (loadbase + get_32be(rsect->s_scnptr)),
+ initrd_size);
+ end_avail = (char *) initrd_start;
+ } else {
+ end_avail = (char *) RAM_END;
+ }
+
+ im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
+ len = get_32be(isect->s_size);
+ dst = (void *) RAM_START;
+
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ void *cp = (void *) RAM_FREE;
+ avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
+ memcpy(cp, im, len);
+ printf("gunzipping... ");
+ gunzip(dst, 0x400000, cp, &len);
+ printf("done\n");
+
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+
+ sa = *(unsigned *)dst + RAM_START;
+ printf("start address = 0x%x\n", sa);
+
+#if 0
+ pause();
+#endif
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d\n", r);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S
new file mode 100644
index 000000000..ae08ee2fa
--- /dev/null
+++ b/arch/ppc/coffboot/misc.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+ .text
+
+/*
+ * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ */
+ .globl setup_bats
+setup_bats:
+ mfpvr 3
+ rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
+ cmpi 0,3,1
+ lis 4,0xc000
+ bne 4f
+ ori 4,4,4 /* set up BAT registers for 601 */
+ li 5,0x7f
+ b 5f
+4: ori 4,4,0xff /* set up BAT registers for 604 */
+ li 5,2
+ mtdbatu 0,4
+ mtdbatl 0,5
+5: mtibatu 0,4
+ mtibatl 0,5
+ isync
+ blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+ .global flush_cache
+flush_cache:
+ addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
+ rlwinm. 4,4,27,5,31
+ mtctr 4
+ beqlr
+1: dcbf 0,3
+ icbi 0,3
+ addi 3,3,0x20
+ bdnz 1b
+ sync
+ isync
+ blr
diff --git a/arch/ppc/coffboot/nonstdio.h b/arch/ppc/coffboot/nonstdio.h
new file mode 100644
index 000000000..664b8384a
--- /dev/null
+++ b/arch/ppc/coffboot/nonstdio.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+typedef int FILE;
+extern FILE *stdin, *stdout;
+#define NULL ((void *)0)
+#define EOF (-1)
+#define fopen(n, m) NULL
+#define fflush(f) 0
+#define fclose(f) 0
+extern char *fgets();
+
+#define perror(s) printf("%s: no files!\n", (s))
diff --git a/arch/ppc/coffboot/rs6000.h b/arch/ppc/coffboot/rs6000.h
new file mode 100644
index 000000000..0def1d95d
--- /dev/null
+++ b/arch/ppc/coffboot/rs6000.h
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+ FIXME: Can someone provide a transliteration of this name into ASCII?
+ Using the following chars caused a compiler warning on HIUX (so I replaced
+ them with octal escapes), and isn't useful without an understanding of what
+ character set it is.
+ Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+ and John Gilmore of Cygnus Support. */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
+ /* IBM RS/6000 */
+#define U802WRMAGIC 0730 /* writeable text segments **chh** */
+#define U802ROMAGIC 0735 /* readonly sharable text segments */
+#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
+
+#define BADMAG(x) \
+ ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+ (x).f_magic != U802TOCMAGIC)
+
+#define FILHDR struct external_filehdr
+#define FILHSZ 20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+ unsigned char magic[2]; /* type of file */
+ unsigned char vstamp[2]; /* version stamp */
+ unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
+ unsigned char dsize[4]; /* initialized data " " */
+ unsigned char bsize[4]; /* uninitialized data " " */
+ unsigned char entry[4]; /* entry pt. */
+ unsigned char text_start[4]; /* base of text used for this file */
+ unsigned char data_start[4]; /* base of data used for this file */
+ unsigned char o_toc[4]; /* address of TOC */
+ unsigned char o_snentry[2]; /* section number of entry point */
+ unsigned char o_sntext[2]; /* section number of .text section */
+ unsigned char o_sndata[2]; /* section number of .data section */
+ unsigned char o_sntoc[2]; /* section number of TOC */
+ unsigned char o_snloader[2]; /* section number of .loader section */
+ unsigned char o_snbss[2]; /* section number of .bss section */
+ unsigned char o_algntext[2]; /* .text alignment */
+ unsigned char o_algndata[2]; /* .data alignment */
+ unsigned char o_modtype[2]; /* module type (??) */
+ unsigned char o_cputype[2]; /* cpu type */
+ unsigned char o_maxstack[4]; /* max stack size (??) */
+ unsigned char o_maxdata[4]; /* max data size (??) */
+ unsigned char o_resv2[12]; /* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */
+#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */
+#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+ char s_name[8]; /* section name */
+ char s_paddr[4]; /* physical address, aliased s_nlib */
+ char s_vaddr[4]; /* virtual address */
+ char s_size[4]; /* section size */
+ char s_scnptr[4]; /* file ptr to raw data for section */
+ char s_relptr[4]; /* file ptr to relocation */
+ char s_lnnoptr[4]; /* file ptr to line numbers */
+ char s_nreloc[2]; /* number of relocation entries */
+ char s_nlnno[2]; /* number of line number entries*/
+ char s_flags[4]; /* flags */
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _PAD ".pad"
+#define _LOADER ".loader"
+
+#define SCNHDR struct external_scnhdr
+#define SCNHSZ 40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER. */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG. */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+ another section header with STYP_OVRFLO set. */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+ union {
+ char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
+ char l_paddr[4]; /* (physical) address of line number */
+ } l_addr;
+ char l_lnno[2]; /* line number */
+};
+
+
+#define LINENO struct external_lineno
+#define LINESZ 6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN 8 /* # characters in a symbol name */
+#define E_FILNMLEN 14 /* # characters in a file name */
+#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+ union {
+ char e_name[E_SYMNMLEN];
+ struct {
+ char e_zeroes[4];
+ char e_offset[4];
+ } e;
+ } e;
+ char e_value[4];
+ char e_scnum[2];
+ char e_type[2];
+ char e_sclass[1];
+ char e_numaux[1];
+};
+
+
+
+#define N_BTMASK (017)
+#define N_TMASK (060)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+
+union external_auxent {
+ struct {
+ char x_tagndx[4]; /* str, un, or enum tag indx */
+ union {
+ struct {
+ char x_lnno[2]; /* declaration line number */
+ char x_size[2]; /* str/union/array size */
+ } x_lnsz;
+ char x_fsize[4]; /* size of function */
+ } x_misc;
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ char x_lnnoptr[4]; /* ptr to fcn line # */
+ char x_endndx[4]; /* entry ndx past block end */
+ } x_fcn;
+ struct { /* if ISARY, up to 4 dimen. */
+ char x_dimen[E_DIMNUM][2];
+ } x_ary;
+ } x_fcnary;
+ char x_tvndx[2]; /* tv index */
+ } x_sym;
+
+ union {
+ char x_fname[E_FILNMLEN];
+ struct {
+ char x_zeroes[4];
+ char x_offset[4];
+ } x_n;
+ } x_file;
+
+ struct {
+ char x_scnlen[4]; /* section length */
+ char x_nreloc[2]; /* # relocation entries */
+ char x_nlinno[2]; /* # line numbers */
+ } x_scn;
+
+ struct {
+ char x_tvfill[4]; /* tv fill value */
+ char x_tvlen[2]; /* length of .tv */
+ char x_tvran[2][2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+ struct {
+ unsigned char x_scnlen[4];
+ unsigned char x_parmhash[4];
+ unsigned char x_snhash[2];
+ unsigned char x_smtyp[1];
+ unsigned char x_smclas[1];
+ unsigned char x_stab[4];
+ unsigned char x_snstab[2];
+ } x_csect;
+
+};
+
+#define SYMENT struct external_syment
+#define SYMESZ 18
+#define AUXENT union external_auxent
+#define AUXESZ 18
+#define DBXMASK 0x80 /* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+ char r_vaddr[4];
+ char r_symndx[4];
+ char r_size[1];
+ char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/ppc/coffboot/start.c b/arch/ppc/coffboot/start.c
new file mode 100644
index 000000000..363e65962
--- /dev/null
+++ b/arch/ppc/coffboot/start.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+
+int (*prom)();
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+
+void
+start(int a1, int a2, void *promptr)
+{
+ prom = (int (*)()) promptr;
+ chosen_handle = finddevice("/chosen");
+ if (chosen_handle == (void *) -1)
+ exit();
+ if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+ exit();
+ stderr = stdout;
+ if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+ exit();
+
+ coffboot(a1, a2, promptr);
+ for (;;)
+ exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "write";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "read";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+void
+exit()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ for (;;) {
+ args.service = "exit";
+ (*prom)(&args);
+ }
+}
+
+void
+pause()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ args.service = "enter";
+ (*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ const char *devspec;
+ void *phandle;
+ } args;
+
+ args.service = "finddevice";
+ args.nargs = 1;
+ args.nret = 1;
+ args.devspec = name;
+ args.phandle = (void *) -1;
+ (*prom)(&args);
+ return args.phandle;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *phandle;
+ const char *name;
+ void *buf;
+ int buflen;
+ int size;
+ } args;
+
+ args.service = "getprop";
+ args.nargs = 4;
+ args.nret = 1;
+ args.phandle = phandle;
+ args.name = name;
+ args.buf = buf;
+ args.buflen = buflen;
+ args.size = -1;
+ (*prom)(&args);
+ return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+ char ch = c;
+
+ if (c == '\n')
+ putc('\r', f);
+ return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+ return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+ int n = strlen(str);
+
+ return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar()
+{
+ char ch;
+
+ for (;;) {
+ switch (read(stdin, &ch, 1)) {
+ case 1:
+ return ch;
+ case -1:
+ printk("read(stdin) returned -1\r\n");
+ return -1;
+ }
+ }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar()
+{
+ int c;
+
+ if (lineleft == 0) {
+ lineptr = line;
+ for (;;) {
+ c = readchar();
+ if (c == -1 || c == 4)
+ break;
+ if (c == '\r' || c == '\n') {
+ *lineptr++ = '\n';
+ putchar('\n');
+ break;
+ }
+ switch (c) {
+ case 0177:
+ case '\b':
+ if (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ case 'U' & 0x1F:
+ while (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ default:
+ if (lineptr >= &line[sizeof(line) - 1])
+ putchar('\a');
+ else {
+ putchar(c);
+ *lineptr++ = c;
+ }
+ }
+ }
+ lineleft = lineptr - line;
+ lineptr = line;
+ }
+ if (lineleft == 0)
+ return -1;
+ --lineleft;
+ return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+ return n;
+}
diff --git a/arch/ppc/coffboot/string.S b/arch/ppc/coffboot/string.S
new file mode 100644
index 000000000..ba83591b7
--- /dev/null
+++ b/arch/ppc/coffboot/string.S
@@ -0,0 +1,206 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define r0 0
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ blelr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
diff --git a/arch/ppc/coffboot/zlib.c b/arch/ppc/coffboot/zlib.c
new file mode 100644
index 000000000..12d07df41
--- /dev/null
+++ b/arch/ppc/coffboot/zlib.c
@@ -0,0 +1,2143 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets. See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c,v 1.1 1997/08/30 04:51:48 ralf Exp $
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+ /* common constants */
+
+#define DEFLATED 8
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+ /* functions */
+
+#include <string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len) memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void zcfree OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size) \
+ (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+ z_stream *z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+local int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int)); /* initial return code */
+
+local void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_addhistory OF((
+ inflate_blocks_statef *,
+ z_stream *));
+
+local int inflate_packet_flush OF((
+ inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt Nalloc; /* number of these allocated here */
+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
+ union {
+ uInt Base; /* literal, length base, or distance base */
+ inflate_huft *Next; /* pointer to next level of table */
+ } more;
+};
+
+#ifdef DEBUG_ZLIB
+ local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *)); /* distance tree result */
+
+local int inflate_trees_free OF((
+ inflate_huft *, /* tables to free */
+ z_stream *)); /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_stream *));
+
+local int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+local void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+ mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, &c);
+ Trace((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z, &c);
+ ZFREE(z, z->state, sizeof(struct internal_state));
+ z->state = Z_NULL;
+ Trace((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/* if (z->zfree == Z_NULL) z->zfree = zcfree; */
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Trace((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+ return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = "unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ if ((b = NEXTBYTE) & 0x20)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid reserved bit";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib header ok\n"));
+ z->state->mode = BLOCKS;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+ r = inflate_packet_flush(z->state->blocks);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r != Z_STREAM_END)
+ return r;
+ r = Z_OK;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ empty:
+ if (f != Z_PACKET_FLUSH)
+ return r;
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+ if (z->state->mode != BLOCKS)
+ return Z_DATA_ERROR;
+ return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONEB, /* finished last block, done */
+ BADB} /* got a data error--stuck here */
+ mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ int nblens; /* # elements allocated at blens */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_huft *tl, *td; /* trees to free */
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ if (s->checkfn != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ if (s->mode == CODES)
+ {
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ }
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(0L, Z_NULL, 0);
+ Trace((stderr, "inflate: blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Trace((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, &s->check);
+ return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Trace((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Trace((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
+ s->sub.decode.td = Z_NULL;
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Trace((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BADB;
+ z->msg = "invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if (((~b) >> 16) != (b & 0xffff))
+ {
+ s->mode = BADB;
+ z->msg = "invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : TYPE;
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BADB;
+ z->msg = "too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if (t < 19)
+ t = 19;
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.trees.nblens = t;
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BADB;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->word.what.Bits;
+ c = h->more.Base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ s->mode = BADB;
+ z->msg = "invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ inflate_trees_free(s->sub.trees.tb, z);
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BADB;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ inflate_trees_free(td, z);
+ inflate_trees_free(tl, z);
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ s->sub.decode.codes = c;
+ s->sub.decode.tl = tl;
+ s->sub.decode.td = td;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONEB;
+ case DONEB:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADB:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ inflate_blocks_reset(s, z, c);
+ ZFREE(z, s->window, s->end - s->window);
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ Trace((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ uLong b; /* bit buffer */ /* NOT USED HERE */
+ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
+ uInt t; /* temporary storage */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ if (s->read != s->write)
+ return Z_STREAM_ERROR;
+ if (s->mode != TYPE)
+ return Z_DATA_ERROR;
+
+ /* we're ready to rock */
+ LOAD
+ /* while there is input ready, copy to output buffer, moving
+ * pointers as needed.
+ */
+ while (n) {
+ t = n; /* how many to do */
+ /* is there room until end of buffer? */
+ if (t > m) t = m;
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, t);
+ zmemcpy(q, p, t);
+ q += t;
+ p += t;
+ n -= t;
+ z->total_out += t;
+ s->read = q; /* drag read pointer forward */
+/* WRAP */ /* expand WRAP macro by hand to handle s->read */
+ if (q == s->end) {
+ s->read = q = s->window;
+ m = WAVAIL;
+ }
+ }
+ UPDATE
+ return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+ inflate_blocks_statef *s;
+{
+ if (s->mode != LENS)
+ return Z_DATA_ERROR;
+ s->mode = TYPE;
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ uIntf *, /* list of base values for non-simple codes */
+ uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ z_stream *)); /* for zalloc function */
+
+local voidpf falloc OF((
+ voidpf, /* opaque pointer (not used) */
+ uInt, /* number of items */
+ uInt)); /* size of item */
+
+local void ffree OF((
+ voidpf q, /* opaque pointer (not used) */
+ voidpf p, /* what to free (not used) */
+ uInt n)); /* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+ uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= N_MAX) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+uIntf *d; /* list of base values for non-simple codes */
+uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+z_stream *zs; /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ uInt v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (inflate_huft *)ZALLOC
+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+ {
+ if (h)
+ inflate_trees_free(u[0], zs);
+ return Z_MEM_ERROR; /* not enough memory */
+ }
+ q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+ inflate_hufts += z + 1;
+#endif
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->next)) = Z_NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ r.next = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tb, z);
+ z->msg = "incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ /* build literal/length tree */
+ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tl, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+ }
+
+ /* build distance tree */
+ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ inflate_trees_free(*td, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ inflate_trees_free(*tl, z);
+ return r;
+#endif
+ }
+
+ /* done */
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530 /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q; /* opaque pointer (not used) */
+uInt n; /* number of items */
+uInt s; /* size of item */
+{
+ Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+ "inflate_trees falloc overflow");
+ if (q) s++; /* to make some compilers happy */
+ fixed_left -= n;
+ return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+ Assert(0, "inflate_trees ffree called!");
+ if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+{
+ /* build fixed tables if not built already--lock out other instances */
+ while (++fixed_lock > 1)
+ fixed_lock--;
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ unsigned c[288]; /* length list for huft_build */
+ z_stream z; /* for falloc function */
+
+ /* set up fake z_stream for memory routines */
+ z.zalloc = falloc;
+ z.zfree = ffree;
+ z.opaque = Z_NULL;
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 7;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+ /* done */
+ fixed_built = 1;
+ }
+ fixed_lock--;
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t; /* table to free */
+z_stream *z; /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register inflate_huft *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != Z_NULL)
+ {
+ q = (--p)->next;
+ ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+ p = q;
+ }
+ return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+ mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+ ZFREE(z, c, sizeof(struct inflate_codes_state));
+ Tracev((stderr, "inflate: codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt n;
+ Bytef *p, *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+ else
+ {
+ z->msg = "invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = "invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf) {s1 += *buf++; s2 += s1;}
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+ uLong adler;
+ Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ k -= 16;
+ }
+ if (k != 0) do {
+ DO1(buf);
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/arch/ppc/coffboot/zlib.h b/arch/ppc/coffboot/zlib.h
new file mode 100644
index 000000000..f4ab77617
--- /dev/null
+++ b/arch/ppc/coffboot/zlib.h
@@ -0,0 +1,432 @@
+/* $Id: zlib.h,v 1.1 1997/08/30 04:51:49 ralf Exp $ */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ * ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 0.95, Aug 16th, 1995.
+
+ Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */ /* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+# define STDC
+# endif
+#endif
+
+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+# include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidp opaque; /* private data object passed to zalloc and zfree */
+
+ Byte data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH 2
+#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
+#define Z_FINISH 4
+#define Z_PACKET_FLUSH 5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Used to set the data_type field */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ */
+
+ /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/*
+ Initializes the internal stream state for decompression. The fields
+ zalloc and zfree must be initialized before by the caller. If zalloc and
+ zfree are set to Z_NULL, inflateInit updates them to use default allocation
+ functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory. msg is set to null if there is no error message.
+ inflateInit does not perform any decompression: this will be done by
+ inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() always provides as much output as possible
+ (until there is no more input data or no more space in the output buffer).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate().
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+ inflate flushes as much output as possible to the output buffer. The
+ flushing behavior of inflate is not specified for values of the flush
+ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+ current implementation actually flushes as much output as possible
+ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
+ has been consumed, it is expecting to see the length field of a stored
+ block; if not, it returns Z_DATA_ERROR.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+ the stream structure was inconsistent (for example if next_in or next_out
+ was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+ progress is possible or if there was not enough room in the output buffer
+ when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+ call inflateSync to look for a good compression block. */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+ int windowBits));
+/*
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc and zfree must be initialized before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+ This function adds the data at next_in (avail_in bytes) to the output
+ history without performing any output. There must be no pending output,
+ and the decompressor must be expecting to see the start of a block.
+ Calling this function is equivalent to decompressing a stored block
+ containing the data at next_in (except that the data is not output).
+*/
+
+ /* checksum functions */
+
+/*
+ This function is not related to compression but is exported
+ anyway because it might be useful in applications using the
+ compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 9df35fa24..1cea7ce3f 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -1,36 +1,44 @@
-#
+# $Id: config.in,v 1.19 1997/09/04 01:54:26 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
-if [ "`uname`" != "Linux" ]; then
+mainmenu_option next_comment
+comment 'Platform support'
+define_bool CONFIG_PPC y
+
+if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then
define_bool CONFIG_CROSSCOMPILE y
else
define_bool CONFIG_NATIVE y
fi
-bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
-bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
-bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+bool 'Build PowerMac Kernel (not PReP or CHRP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac or CHRP)?' CONFIG_PREP
+bool 'Build CHRP Kernel (not PReP or PowerMac)?' CONFIG_CHRP
+
choice 'Processor type' \
- "Common CONFIG_MCOMMON \
- 601 CONFIG_M601 \
- 603 CONFIG_M603 \
- 604 CONFIG_M604" Common
+ "Common CONFIG_COMMON \
+ 601 CONFIG_601 \
+ 603 CONFIG_603 \
+ 604 CONFIG_604" Common
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-
-mainmenu_option next_comment
define_bool CONFIG_PCI y
-bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+if [ "$CONFIG_PREP" = "y" ]; then
+ bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+fi
bool 'Networking support' CONFIG_NET
bool 'Sysctl support' CONFIG_SYSCTL
bool 'System V IPC' CONFIG_SYSVIPC
@@ -39,8 +47,24 @@ bool 'System V IPC' CONFIG_SYSVIPC
define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_KERNEL_ELF y
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
+
+if [ "$CONFIG_PMAC" = "y" ]; then
+ define_bool CONFIG_PMAC_CONSOLE y
+ define_bool CONFIG_MAC_KEYBOARD y
+ define_bool CONFIG_MAC_FLOPPY y
+ bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+ bool 'Include xmon kernel debugger' CONFIG_XMON
+fi
+
+if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
+ bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO
+ bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO
+else
+ define_bool CONFIG_VGA_CONSOLE y
+fi
+endmenu
source drivers/pnp/Config.in
source drivers/block/Config.in
@@ -83,6 +107,7 @@ fi
endmenu
source fs/Config.in
+
source drivers/char/Config.in
mainmenu_option next_comment
@@ -93,12 +118,12 @@ if [ "$CONFIG_SOUND" != "n" ]; then
fi
endmenu
-mainmenu_option next_comment
+#mainmenu_option next_comment
#comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
#bool 'Kernel profiling support' CONFIG_PROFILE
#if [ "$CONFIG_PROFILE" = "y" ]; then
# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
#fi
-endmenu
+#endmenu
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
new file mode 100644
index 000000000..ea39e83ea
--- /dev/null
+++ b/arch/ppc/defconfig
@@ -0,0 +1,250 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+CONFIG_MCOMMON=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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 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
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 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_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET 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=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+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
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/ignore b/arch/ppc/ignore
new file mode 100644
index 000000000..693fff61a
--- /dev/null
+++ b/arch/ppc/ignore
@@ -0,0 +1,65 @@
+.config
+compile.h
+.version
+.objects
+.blurb
+*.cort
+*.paul
+*.old
+.defines
+version.h
+find_name
+checks
+#*
+.objects
+.object_files
+System.map
+asm
+.menuconfig*
+CVS
+ppc_defs.h
+mk_defs
+mkprep
+*.s
+.depend
+.hdepend
+*~
+*.o
+znetboot
+zvmlinux
+vmlinux
+zImage
+hack-coff
+coffboot
+vmlinux.coff
+.depend
+.cvsignore
+RCS
+SCCS
+CVS.adm
+RCSLOG
+cvslog.*
+tags
+TAGS
+.make.state
+.nse_depinfo
+*~
+#*
+.#*
+,*
+_$*
+*$
+*.old
+*.bak
+*.BAK
+*.orig
+*.rej
+*.a
+*.olb
+*.o
+*.obj
+*.so
+*.exe
+*.Z
+*.elc
+*.ln
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 941cd9e38..6fd50a6fb 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -7,39 +7,21 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-HOST_CC = gcc
-
-OBJS = misc.o port_io.o pci.o traps.o process.o \
- signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
+O_TARGET := kernel.o
+O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
+ align.o ptrace.o irq.o openpic.o bitops.o ppc_htab.o idle.o \
+ time.o prep_time.o pmac_time.o chrp_time.o \
+ setup.o prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
+ pci.o prep_pci.o pmac_pci.o chrp_pci.o \
+ residual.o prom.o
+OX_OBJS := ppc_ksyms.o
all: head.o kernel.o
-head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
-
-ifeq ($(CONFIG_PREP),y)
-OBJS += prep_setup.o prep_time.o
-endif
-
-ifeq ($(CONFIG_PMAC),y)
-OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
-endif
-
-ifeq ($(CONFIG_MODULES),y)
-OBJS = ksyms.o
-endif
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
ppc_defs.h: mk_defs.c ppc_defs.head \
$(TOPDIR)/include/asm/mmu.h \
@@ -52,25 +34,7 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
rm mk_defs.s
checks: checks.c
- $(HOSTCC) ${CFLAGS} -o checks checks.c
- checks
-
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
+ $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+ ./checks
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
-
-modules:
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
new file mode 100644
index 000000000..39cb04f77
--- /dev/null
+++ b/arch/ppc/kernel/align.c
@@ -0,0 +1,290 @@
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct aligninfo {
+ unsigned char len;
+ unsigned char flags;
+};
+
+#define INVALID { 0, 0 }
+
+#define LD 1 /* load */
+#define ST 2 /* store */
+#define SE 4 /* sign-extend value */
+#define F 8 /* to/from fp regs */
+#define U 0x10 /* update index register */
+#define M 0x20 /* multiple load/store */
+#define S 0x40 /* single-precision fp, or byte-swap value */
+#define HARD 0x80 /* string, stwcx. */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register. This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+ { 4, LD }, /* 00 0 0000: lwz / lwarx */
+ INVALID, /* 00 0 0001 */
+ { 4, ST }, /* 00 0 0010: stw */
+ INVALID, /* 00 0 0011 */
+ { 2, LD }, /* 00 0 0100: lhz */
+ { 2, LD+SE }, /* 00 0 0101: lha */
+ { 2, ST }, /* 00 0 0110: sth */
+ { 4, LD+M }, /* 00 0 0111: lmw */
+ { 4, LD+F+S }, /* 00 0 1000: lfs */
+ { 8, LD+F }, /* 00 0 1001: lfd */
+ { 4, ST+F+S }, /* 00 0 1010: stfs */
+ { 8, ST+F }, /* 00 0 1011: stfd */
+ INVALID, /* 00 0 1100 */
+ INVALID, /* 00 0 1101 */
+ INVALID, /* 00 0 1110 */
+ INVALID, /* 00 0 1111 */
+ { 4, LD+U }, /* 00 1 0000: lwzu */
+ INVALID, /* 00 1 0001 */
+ { 4, ST+U }, /* 00 1 0010: stwu */
+ INVALID, /* 00 1 0011 */
+ { 2, LD+U }, /* 00 1 0100: lhzu */
+ { 2, LD+SE+U }, /* 00 1 0101: lhau */
+ { 2, ST+U }, /* 00 1 0110: sthu */
+ { 4, ST+M }, /* 00 1 0111: stmw */
+ { 4, LD+F+S+U }, /* 00 1 1000: lfsu */
+ { 8, LD+F+U }, /* 00 1 1001: lfdu */
+ { 4, ST+F+S+U }, /* 00 1 1010: stfsu */
+ { 8, ST+F+U }, /* 00 1 1011: stfdu */
+ INVALID, /* 00 1 1100 */
+ INVALID, /* 00 1 1101 */
+ INVALID, /* 00 1 1110 */
+ INVALID, /* 00 1 1111 */
+ INVALID, /* 01 0 0000 */
+ INVALID, /* 01 0 0001 */
+ INVALID, /* 01 0 0010 */
+ INVALID, /* 01 0 0011 */
+ INVALID, /* 01 0 0100 */
+ INVALID, /* 01 0 0101: lwax?? */
+ INVALID, /* 01 0 0110 */
+ INVALID, /* 01 0 0111 */
+ { 0, LD+HARD }, /* 01 0 1000: lswx */
+ { 0, LD+HARD }, /* 01 0 1001: lswi */
+ { 0, ST+HARD }, /* 01 0 1010: stswx */
+ { 0, ST+HARD }, /* 01 0 1011: stswi */
+ INVALID, /* 01 0 1100 */
+ INVALID, /* 01 0 1101 */
+ INVALID, /* 01 0 1110 */
+ INVALID, /* 01 0 1111 */
+ INVALID, /* 01 1 0000 */
+ INVALID, /* 01 1 0001 */
+ INVALID, /* 01 1 0010 */
+ INVALID, /* 01 1 0011 */
+ INVALID, /* 01 1 0100 */
+ INVALID, /* 01 1 0101: lwaux?? */
+ INVALID, /* 01 1 0110 */
+ INVALID, /* 01 1 0111 */
+ INVALID, /* 01 1 1000 */
+ INVALID, /* 01 1 1001 */
+ INVALID, /* 01 1 1010 */
+ INVALID, /* 01 1 1011 */
+ INVALID, /* 01 1 1100 */
+ INVALID, /* 01 1 1101 */
+ INVALID, /* 01 1 1110 */
+ INVALID, /* 01 1 1111 */
+ INVALID, /* 10 0 0000 */
+ INVALID, /* 10 0 0001 */
+ { 0, ST+HARD }, /* 10 0 0010: stwcx. */
+ INVALID, /* 10 0 0011 */
+ INVALID, /* 10 0 0100 */
+ INVALID, /* 10 0 0101 */
+ INVALID, /* 10 0 0110 */
+ INVALID, /* 10 0 0111 */
+ { 4, LD+S }, /* 10 0 1000: lwbrx */
+ INVALID, /* 10 0 1001 */
+ { 4, ST+S }, /* 10 0 1010: stwbrx */
+ INVALID, /* 10 0 1011 */
+ { 2, LD+S }, /* 10 0 1100: lhbrx */
+ INVALID, /* 10 0 1101 */
+ { 2, ST+S }, /* 10 0 1110: sthbrx */
+ INVALID, /* 10 0 1111 */
+ INVALID, /* 10 1 0000 */
+ INVALID, /* 10 1 0001 */
+ INVALID, /* 10 1 0010 */
+ INVALID, /* 10 1 0011 */
+ INVALID, /* 10 1 0100 */
+ INVALID, /* 10 1 0101 */
+ INVALID, /* 10 1 0110 */
+ INVALID, /* 10 1 0111 */
+ INVALID, /* 10 1 1000 */
+ INVALID, /* 10 1 1001 */
+ INVALID, /* 10 1 1010 */
+ INVALID, /* 10 1 1011 */
+ INVALID, /* 10 1 1100 */
+ INVALID, /* 10 1 1101 */
+ INVALID, /* 10 1 1110 */
+ { 0, ST+HARD }, /* 10 1 1111: dcbz */
+ { 4, LD }, /* 11 0 0000: lwzx */
+ INVALID, /* 11 0 0001 */
+ { 4, ST }, /* 11 0 0010: stwx */
+ INVALID, /* 11 0 0011 */
+ { 2, LD }, /* 11 0 0100: lhzx */
+ { 2, LD+SE }, /* 11 0 0101: lhax */
+ { 2, ST }, /* 11 0 0110: sthx */
+ INVALID, /* 11 0 0111 */
+ { 4, LD+F+S }, /* 11 0 1000: lfsx */
+ { 8, LD+F }, /* 11 0 1001: lfdx */
+ { 4, ST+F+S }, /* 11 0 1010: stfsx */
+ { 8, ST+F }, /* 11 0 1011: stfdx */
+ INVALID, /* 11 0 1100 */
+ INVALID, /* 11 0 1101 */
+ INVALID, /* 11 0 1110 */
+ INVALID, /* 11 0 1111 */
+ { 4, LD+U }, /* 11 1 0000: lwzux */
+ INVALID, /* 11 1 0001 */
+ { 4, ST+U }, /* 11 1 0010: stwux */
+ INVALID, /* 11 1 0011 */
+ { 2, LD+U }, /* 11 1 0100: lhzux */
+ { 2, LD+SE+U }, /* 11 1 0101: lhaux */
+ { 2, ST+U }, /* 11 1 0110: sthux */
+ INVALID, /* 11 1 0111 */
+ { 4, LD+F+S+U }, /* 11 1 1000: lfsux */
+ { 8, LD+F+U }, /* 11 1 1001: lfdux */
+ { 4, ST+F+S+U }, /* 11 1 1010: stfsux */
+ { 8, ST+F+U }, /* 11 1 1011: stfdux */
+ INVALID, /* 11 1 1100 */
+ INVALID, /* 11 1 1101 */
+ INVALID, /* 11 1 1110 */
+ INVALID, /* 11 1 1111 */
+};
+
+#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+ int instr, nb, flags;
+ int i, t;
+ int reg, areg;
+ unsigned char *addr;
+ union {
+ long l;
+ float f;
+ double d;
+ unsigned char v[8];
+ } data;
+
+ instr = (regs->dsisr >> 10) & 0x7f;
+ nb = aligninfo[instr].len;
+ if (nb == 0)
+ return 0; /* too hard or invalid instruction bits */
+ flags = aligninfo[instr].flags;
+ addr = (unsigned char *) regs->dar;
+ reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */
+
+ /* Verify the address of the operand */
+ if (user_mode(regs)) {
+ if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+ return -EFAULT; /* bad address */
+ }
+
+ if ((flags & F) && last_task_used_math == current)
+ giveup_fpu();
+
+ if (flags & M)
+ return 0; /* too hard for now */
+
+ /* If we read the operand, copy it in */
+ if (flags & LD) {
+ if (nb == 2) {
+ data.v[0] = data.v[1] = 0;
+ if (__get_user(data.v[2], addr)
+ || __get_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__get_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ switch (flags & ~U) {
+ case LD+SE:
+ if (data.v[2] >= 0x80)
+ data.v[0] = data.v[1] = -1;
+ /* fall through */
+ case LD:
+ regs->gpr[reg] = data.l;
+ break;
+ case LD+S:
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ regs->gpr[reg] = data.l;
+ break;
+ case ST:
+ data.l = regs->gpr[reg];
+ break;
+ case ST+S:
+ data.l = regs->gpr[reg];
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ break;
+ case LD+F:
+ current->tss.fpr[reg] = data.d;
+ break;
+ case ST+F:
+ data.d = current->tss.fpr[reg];
+ break;
+ /* these require some floating point conversions... */
+ /* note that giveup_fpu enables the FPU for the kernel */
+ /* we'd like to use the assignment, but we have to compile
+ * the kernel with -msoft-float so it doesn't use the
+ * fp regs for copying 8-byte objects. */
+ case LD+F+S:
+ giveup_fpu();
+ cvt_fd(&data.f, &current->tss.fpr[reg]);
+ /* current->tss.fpr[reg] = data.f; */
+ break;
+ case ST+F+S:
+ giveup_fpu();
+ cvt_df(&current->tss.fpr[reg], &data.f);
+ /* data.f = current->tss.fpr[reg]; */
+ break;
+ default:
+ printk("align: can't handle flags=%x\n", flags);
+ return 0;
+ }
+
+ if (flags & ST) {
+ if (nb == 2) {
+ if (__put_user(data.v[2], addr)
+ || __put_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__put_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ if (flags & U) {
+ areg = regs->dsisr & 0x1f; /* register to update */
+ regs->gpr[areg] = regs->dar;
+ }
+
+ return 1;
+}
diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
new file mode 100644
index 000000000..fb5a19e3a
--- /dev/null
+++ b/arch/ppc/kernel/bitops.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+
+/*
+ * I left these here since the problems with "cc" make it difficult to keep
+ * them in bitops.h -- Cort
+ */
+void set_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ or %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void clear_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ andc %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void change_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ xor %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+int test_and_set_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ or %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_clear_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_change_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+/* I put it in bitops.h -- Cort */
+#if 0
+int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+int find_first_zero_bit(void * addr, int size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+int find_next_zero_bit(void * addr, int size, int offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+#endif
diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c
new file mode 100644
index 000000000..312229552
--- /dev/null
+++ b/arch/ppc/kernel/checks.c
@@ -0,0 +1,57 @@
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+
+/*
+ * Do various before compile checks of data structures
+ * -- Cort
+ */
+int main(void)
+{
+ int ret = 0;
+#if 0
+ if ( sizeof(struct thread_struct) % 16 )
+ {
+ printf("Thread struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct thread_struct),
+ sizeof(struct thread_struct)%16);
+ ret = -1;
+ }
+#endif
+
+ if ( sizeof(struct pt_regs) % 16 )
+ {
+ printf("pt_regs struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct pt_regs),
+ sizeof(struct pt_regs)%16);
+ ret = -1;
+
+ }
+
+ printf("Task size : %d bytes\n"
+ "Tss size : %d bytes\n"
+ "pt_regs size : %d bytes\n"
+ "Kernel stack size: %d bytes\n",
+ sizeof(struct task_struct), sizeof(struct thread_struct),
+ sizeof(struct pt_regs),
+ sizeof(union task_union) - sizeof(struct task_struct));
+ return ret;
+}
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
new file mode 100644
index 000000000..8af9ba9d6
--- /dev/null
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -0,0 +1,156 @@
+/*
+ * CHRP pci routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/openpic.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+
+/* LongTrail */
+#define pci_config_addr(bus, dev, offset) \
+ (0xfec00000 | ((bus)<<16) | ((dev)<<8) | (offset))
+
+int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ if (bus > 7) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+ if (offset == PCI_INTERRUPT_LINE) {
+ /* PCI interrupts are controlled by the OpenPIC */
+ if (*val)
+ *val = openpic_to_irq(*val);
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ if (bus > 7) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ if (bus > 7) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int num, devfn;
+ unsigned int x, vendev;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (devfn = 0; devfn < 32; devfn++) {
+ chrp_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+ if (x == vendev) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devfn<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int devnr, x, num;
+
+ num = 0;
+ for (devnr = 0; devnr < 32; devnr++) {
+ chrp_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+ if ((x>>8) == class_code) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devnr<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(volatile struct Hydra *find_hydra(void))
+{
+ u_char bus, dev;
+ volatile struct Hydra *hydra = 0;
+ if (chrp_pcibios_find_device(PCI_VENDOR_ID_APPLE,
+ PCI_DEVICE_ID_APPLE_HYDRA, 0, &bus, &dev)
+ == PCIBIOS_SUCCESSFUL)
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
+ (unsigned int *)&hydra);
+ return hydra;
+}
+
+__initfunc(void hydra_post_openpic_init(void))
+{
+ openpic_set_sense(HYDRA_INT_SCSI_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCA_TX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCA_RX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCB_TX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCB_RX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCSI, 1);
+ openpic_set_sense(HYDRA_INT_SCCA, 1);
+ openpic_set_sense(HYDRA_INT_SCCB, 1);
+ openpic_set_sense(HYDRA_INT_VIA, 1);
+ openpic_set_sense(HYDRA_INT_ADB, 1);
+ openpic_set_sense(HYDRA_INT_ADB_NMI, 0);
+}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
new file mode 100644
index 000000000..0a5544b96
--- /dev/null
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -0,0 +1,180 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+extern unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+
+extern char saved_command_line[256];
+
+long TotalMemory;
+
+int
+chrp_get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+
+ switch (pvr>>16)
+ {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ case 9:
+ model = "604e";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+
+ len = sprintf(buffer, "PowerPC %s rev %d.%d\n", model,
+ (pvr & 0xff00) >> 8, pvr & 0xff);
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ (loops_per_sec+2500)/500000,
+ ((loops_per_sec+2500)/5000) % 100);
+
+#if 0
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+ "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
+ }
+#endif
+ return len;
+}
+
+__initfunc(void
+chrp_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
+{
+ extern char cmd_line[];
+ extern char _etext[], _edata[], _end[];
+ extern int panic_timeout;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy( saved_command_line, cmd_line );
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = (unsigned long) Hash+Hash_size;
+ (unsigned long *)*memory_end_p = (unsigned long *)(TotalMemory+KERNELBASE);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_sec = 50000000;
+
+ /* reboot on panic */
+ panic_timeout = 180;
+
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) _etext;
+ init_task.mm->end_data = (unsigned long) _edata;
+ init_task.mm->brk = (unsigned long) _end;
+
+ aux_device_present = 0xaa;
+
+ switch ( _machine )
+ {
+ case _MACH_chrp:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+ break;
+ }
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+ /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+ if ( initrd_start )
+ {
+ if (initrd_end > *memory_end_p)
+ {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end,*memory_end_p);
+ initrd_start = 0;
+ }
+ }
+#endif
+
+ printk("Boot arguments: %s\n", cmd_line);
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
new file mode 100644
index 000000000..bf58953cd
--- /dev/null
+++ b/arch/ppc/kernel/chrp_time.c
@@ -0,0 +1,132 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+int chrp_cmos_clock_read(int addr)
+{
+ outb(addr>>8, NVRAM_AS1);
+ outb(addr, NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+}
+
+void chrp_cmos_clock_write(unsigned long val, int addr)
+{
+ outb(addr>>8, NVRAM_AS1);
+ outb(addr, NVRAM_AS0);
+ outb(val,NVRAM_DATA);
+ return;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int chrp_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ to_tm(nowtime, &tm);
+
+ save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+ chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ chrp_cmos_clock_write(save_control, RTC_CONTROL);
+ chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ return 0;
+}
+
+unsigned long chrp_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = chrp_cmos_clock_read(RTC_SECONDS);
+ min = chrp_cmos_clock_read(RTC_MINUTES);
+ hour = chrp_cmos_clock_read(RTC_HOURS);
+ day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = chrp_cmos_clock_read(RTC_MONTH);
+ year = chrp_cmos_clock_read(RTC_YEAR);
+ } while (sec != chrp_cmos_clock_read(RTC_SECONDS));
+ if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 25f2dd8a0..3038e8cc1 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -45,14 +45,13 @@
#define TOPHYS(x) (x - KERNELBASE)
-
/* this is a very kludgey way of loading up the BATs on the
prep system. I'll kill this horrible macro and write
something clean when I have a chance -- Cort
*/
#define LOAD_BATS(RA,RB) \
mfspr RA,PVR ; \
- srwi r5,r5,16 ; \
+ srwi RA,RA,16 ; \
cmpi 0,RA,1 ; \
beq 199f ; \
/* load bats for 60x */ ; \
@@ -132,21 +131,10 @@
mtspr DBAT3L,RB ; \
200:
-
-
-
.text
.globl _stext
_stext:
-#ifdef CONFIG_PREP
- . = 0x100
-_GLOBAL(HardReset)
- b _start
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
/*
* _start is defined this way because the XCOFF loader in the OpenFirmware
* on the powermac expects the entry point to be a procedure descriptor.
@@ -156,7 +144,7 @@ _GLOBAL(HardReset)
_start:
.long TOPHYS(__start),0,0
-/*
+/* PMAC
* Enter here with the kernel text, data and bss loaded starting at
* 0, running with virtual == physical mapping.
* r5 points to the prom entry point (the client interface handler
@@ -165,41 +153,71 @@ _start:
* pointer (r1) points to just below the end of the half-meg region
* from 0x380000 - 0x400000, which is mapped in already.
*/
+/* PREP
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader. The expected layout
+ * of the regs is:
+ * r3: ptr to residual data
+ * r4: initrd_start or if no initrd then 0
+ * r5: initrd_end - unused if r4 is 0
+ * r6: Start of command line string
+ * r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
+ */
+
.globl __start
__start:
/*
- * Use the first pair of BAT registers to map the 1st 8MB
+ * Use the first pair of BAT registers to map the 1st 16MB
* of RAM to KERNELBASE.
*/
- mfspr r9,PVR
- rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
- cmpi 0,r9,1
- lis r7,KERNELBASE@h
- bne 4f
- ori r7,r7,4 /* set up BAT registers for 601 */
- li r8,0x7f
- b 5f
-4: ori r7,r7,0xff /* set up BAT registers for 604 */
- li r8,2
- mtspr DBAT0U,r7
- mtspr DBAT0L,r8
-5: mtspr IBAT0U,r7
- mtspr IBAT0L,r8
- isync
-
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r11,KERNELBASE@h
+ bne 4f
+ ori r11,r11,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ ori r11,r11,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
+ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
+ mtspr IBAT1U,r9
+ mtspr IBAT1L,r10
+ b 5f
+4: ori r11,r11,0x1ff /* set up BAT registers for 604 */
+ li r8,2
+ mtspr DBAT0U,r11
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r11
+ mtspr IBAT0L,r8
+ isync
/*
- * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
- * refer to addresses of data items, procedures, etc. normally.
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
*/
- lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
- blr
-#endif /* CONFIG_PMAC */
-
-
-
+ mfmsr r0
+ ori r0,r0,MSR_DR|MSR_IR
+ mtspr SRR1,r0
+ lis r0,start_here@h
+ ori r0,r0,start_here@l
+ mtspr SRR0,r0
+ SYNC
+ rfi /* enables MMU */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't. To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD 64
/*
* Macros for storing registers into and loading registers from
@@ -286,10 +304,8 @@ label: \
.long hdlr; \
.long int_return
-#ifndef CONFIG_PREP
/* System reset */
STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif /* ndef CONFIG_PREP */
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -319,7 +335,7 @@ DataAccess:
/* Instruction access exception */
. = 0x400
-InstructionAccess:
+InstructionAccess:
EXCEPTION_PROLOG
andis. r0,r23,0x4000 /* no pte found? */
beq 1f /* if so, try to put a PTE */
@@ -338,7 +354,7 @@ InstructionAccess:
.long int_return
/* External interrupt */
- STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+ STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
/* Alignment exception */
. = 0x600
@@ -376,21 +392,7 @@ FPUnavailable:
.long KernelFP
.long int_return
-/* Decrementer */
-#ifdef CONFIG_PREP
-/* - ignored for now... */
-_ORG(0x0900)
- mtspr SPRG0,r1
- lis r1,0x7FFF
- ori r1,r1,0xFFFF
- mtspr DEC,r1
- mfspr r1,SPRG0
- rfi
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
-#endif /* CONFIG_PMAC */
-
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
@@ -596,11 +598,6 @@ transfer_to_handler:
andi. r23,r23,MSR_PR
mfspr r23,SPRG3 /* if from user, fix up tss */
beq 2f
-#ifdef CONFIG_PMAC
- lwz r24,GPR1(r21)
- stw r22,LAST_PC(r23)
- stw r24,USER_STACK(r23)
-#endif /* CONFIG_PMAC */
addi r24,r1,STACK_FRAME_OVERHEAD
stw r24,PT_REGS(r23)
2: addi r2,r23,-TSS /* set r2 to current */
@@ -630,7 +627,7 @@ load_up_fpu:
REST_32FPRS(0, r5)
/* use last_task_used_math instead of fpu_tss */
- lis r3,last_task_used_math@h/*a*/
+ lis r3,last_task_used_math@ha
addis r3,r3,-KERNELBASE@h
subi r4,r5,TSS
addis r4,r4,KERNELBASE@h
@@ -654,7 +651,7 @@ load_up_fpu:
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
+ SYNC
rfi
/*
@@ -682,14 +679,15 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
.globl hash_page
hash_page:
/* Get PTE (linux-style) and check access */
- lwz r5,PG_TABLES(r5) /* task's page tables */
- lis r2,-KERNELBASE@h
- add r5,r5,r2 /* convert to phys addr */
+ lwz r5,MM-TSS(r5)
+ addis r5,r5,-KERNELBASE@h /* get physical current->mm */
+ lwz r5,PGD(r5) /* get current->mm->pgd */
+ addis r5,r5,-KERNELBASE@h /* convert to phys addr */
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
beqlr- /* return if no mapping */
- add r2,r5,r2
+ addis r2,r5,-KERNELBASE@h
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
@@ -819,58 +817,62 @@ start_here:
rlwinm r9,r9,16,16,31
cmpi 0,r9,1
beq 4f /* not needed for 601 */
- mfspr r7,HID0
- andi. r0,r7,HID0_DCE
- ori r7,r7,HID0_ICE|HID0_DCE
- ori r8,r7,HID0_ICFI
+ mfspr r11,HID0
+ andi. r0,r11,HID0_DCE
+ ori r11,r11,HID0_ICE|HID0_DCE
+ ori r8,r11,HID0_ICFI
bne 3f /* don't invalidate the D-cache */
ori r8,r8,HID0_DCI /* unless it wasn't enabled */
-3: sync
- mtspr HID0,r8 /* enable and invalidate caches */
+3:
+ /* turn on dpm for 603 */
+ cmpi 0,r9,3
+ bne 10f
+ oris r11,r11,HID0_DPM@h
+10:
sync
- mtspr HID0,r7 /* enable caches */
+ mtspr HID0,r8 /* enable and invalidate caches */
+ mtspr HID0,r11 /* enable caches */
sync
isync
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
cror 2,2,6
bne 4f
- ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
- mtspr HID0,r7 /* superscalar exec & br history tbl */
+ ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
/* ptr to current */
lis r2,init_task_union@h
ori r2,r2,init_task_union@l
/* ptr to phys current tss */
- addis r3,r2,-KERNELBASE@h
- addi r3,r3,TSS /* init task's TSS */
- mtspr SPRG3,r3
+ addis r11,r2,-KERNELBASE@h
+ addi r11,r11,TSS /* init task's TSS */
+ mtspr SPRG3,r11
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
/* Clear out the BSS */
- lis r7,_end@ha
- addi r7,r7,_end@l
+ lis r11,_end@ha
+ addi r11,r11,_end@l
lis r8,__bss_start@ha
addi r8,r8,__bss_start@l
- subf r7,r8,r7
- addi r7,r7,3
- rlwinm. r7,r7,30,2,31
+ subf r11,r8,r11
+ addi r11,r11,3
+ rlwinm. r11,r11,30,2,31
beq 2f
addi r8,r8,-4
- mtctr r7
+ mtctr r11
li r0,0
3: stwu r0,4(r8)
bdnz 3b
2:
/*
- * Initialize the prom stuff (powermacs only) and the MMU.
+ * Initialize the prom stuff and the MMU.
*/
-#ifdef CONFIG_PMAC
+ bl identify_machine
bl prom_init
-#endif /* CONFIG_PMAC */
bl MMU_init
/*
@@ -889,11 +891,6 @@ start_here:
rfi
/* Load up the kernel context */
2:
-#ifdef CONFIG_PREP
- /* reload the bats now that MMU_init() has setup them up -- Cort */
- LOAD_BATS(r3,r0)
-#endif
-
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
mtspr SDR1,r6
@@ -905,8 +902,19 @@ start_here:
addi r3,r3,1 /* increment VSID */
addis r4,r4,0x1000 /* address of next segment */
bdnz 3b
-#ifdef CONFIG_PMAC
- li r0,0 /* zot the BATs */
+
+ lis r3,_machine@ha
+ addis r3,r3,-KERNELBASE@h
+ lwz r0,_machine@l(r3)
+ cmpi 0,r0,_MACH_Pmac
+ beq 99f
+
+/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r14)
+ b 100f
+
+/* on pmac clear the bats out */
+99: li r0,0 /* zot the BATs */
#if 1
mtspr IBAT0U,r0
mtspr IBAT0L,r0
@@ -925,7 +933,7 @@ start_here:
mtspr IBAT3L,r0
mtspr DBAT3U,r0
mtspr DBAT3L,r0
-#endif
+100:
/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
lis r3,start_kernel@h
@@ -934,60 +942,29 @@ start_here:
mtspr SRR1,r4
rfi /* enable MMU and jump to start_kernel */
-#ifdef CONFIG_PREP
-/*
- * This is jumped to on prep systems right after the kernel is relocated
- * to its proper place in memory by the boot loader. The expected layout
- * of the regs is:
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort
- */
- .globl __start
-__start:
- .globl _start
-_start:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* save pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- addis r1,r1,-KERNELBASE@h
- stw r3,0(r1)
-/* save argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- addis r1,r1,-KERNELBASE@h
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
-/* setup the msr with sane values */
- li r0,MSR_
- mtmsr r0
-/* turn on the mmu with bats covering kernel enough to get started */
- LOAD_BATS(r3,r0)
+
+ .globl reset_SDR1
+reset_SDR1:
+ lis r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
+ li r4,MSR_IR|MSR_DR
+ andc r3,r3,r4
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
+ rfi
+2: /* load new SDR1 */
+ tlbia
+ mtspr SDR1,r6
+ /* turn the mmu back on */
+ li r4,MSR_KERNEL
+ mflr r3
mtspr SRR0,r3
- SYNC
- rfi /* enables MMU */
-10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
- blr
-#endif /* CONFIG_PREP */
+ mtspr SRR1,r4
+ rfi
/*
* FP unavailable trap from kernel - print a message, but let
@@ -1022,31 +999,23 @@ giveup_fpu_unmapped:
giveup_fpu:
li r6,0
1:
- addis r3,r6,last_task_used_math@h/*a*/
+ addis r3,r6,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
-#if 0
- addis r3,r6,fpu_tss@ha
- lwz r4,fpu_tss@l(r3)
-#endif
mfmsr r5
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
SYNC
cmpi 0,r4,0
+ beqlr- /* if no previous owner, done */
add r4,r4,r6
- beqlr /* if no previous owner, done */
addi r4,r4,TSS /* want TSS of last_task_used_math */
li r5,0
stw r5,last_task_used_math@l(r3)
-#if 0
- stw r5,fpu_tss@l(r3)
-#endif
SAVE_32FPRS(0, r4)
mffs fr0
stfd fr0,TSS_FPSCR-4(r4)
lwz r5,PT_REGS(r4)
- lwz r5,PT_REGS(r4)
add r5,r5,r6
lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
li r4,MSR_FP
@@ -1268,7 +1237,7 @@ int_return:
cmpi 0,r4,0
beq+ 1f
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
b 3b
1: lis r4,bh_mask@ha
lwz r4,bh_mask@l(r4)
@@ -1341,7 +1310,7 @@ _GLOBAL(fake_interrupt)
li r0,0x0fac
stw r0,TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
lwz r0,4(r1)
mtlr r0
@@ -1384,11 +1353,11 @@ _GLOBAL(flush_instruction_cache)
* and invalidate the corresponding instruction cache blocks.
* This is a no-op on the 601.
*
- * store_cache_range(unsigned long start, unsigned long stop)
+ * flush_icache_range(unsigned long start, unsigned long stop)
*/
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
-_GLOBAL(store_cache_range)
+_GLOBAL(flush_icache_range)
mfspr r5,PVR
rlwinm r5,r5,16,16,31
cmpi 0,r5,1
@@ -1521,7 +1490,6 @@ _GLOBAL(flush_hash_page)
_GLOBAL(__main)
blr
-#ifdef CONFIG_PMAC
/*
* These exception handlers are used when we have called a prom
* routine after we have taken over the exception vectors and MMU.
@@ -1716,7 +1684,6 @@ enter_prom:
lwz r31,28(r1)
lwz r1,0(r1)
blr
-#endif
/*
* We put a few things here that have to be page-aligned.
@@ -1726,7 +1693,6 @@ enter_prom:
.data
.globl sdata
sdata:
- .space 2*4096
.globl empty_zero_page
empty_zero_page:
.space 4096
@@ -1735,7 +1701,6 @@ empty_zero_page:
swapper_pg_dir:
.space 4096
-#ifdef CONFIG_PREP
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
@@ -1743,5 +1708,4 @@ swapper_pg_dir:
.globl cmd_line
cmd_line:
.space 512
-#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
new file mode 100644
index 000000000..bfe1a4146
--- /dev/null
+++ b/arch/ppc/kernel/idle.c
@@ -0,0 +1,279 @@
+/*
+ * $Id: idle.c,v 1.4 1997/08/23 22:46:01 cort Exp $
+ *
+ * Idle daemon for PowerPC. Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define __KERNEL_SYSCALLS__
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+#include <asm/processor.h>
+
+int zero_paged(void *unused);
+int power_saved(void *unused);
+
+asmlinkage int sys_idle(void)
+{
+ int ret = -EPERM;
+
+ if (current->pid != 0)
+ goto out;
+
+ /*
+ * want one per cpu since it would be nice to have all
+ * processors who aren't doing anything
+ * zero-ing pages since this daemon is lock-free
+ * -- Cort
+ */
+ kernel_thread(zero_paged, NULL, 0);
+ /* no powersaving modes on 601 */
+ /*if( (_get_PVR()>>16) != 1 )
+ kernel_thread(power_saved, NULL, 0);*/
+
+ /* endless loop with no priority at all */
+ current->priority = -100;
+ current->counter = -100;
+ for (;;)
+ {
+ schedule();
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0; /* # currently pre-zero'd pages */
+unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0; /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
+static struct wait_queue * page_zerod_wait = NULL;
+#define PAGE_THRESHOLD 96 /* how many pages to keep pre-zero'd */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
+{
+ unsigned long page;
+
+ atomic_inc((atomic_t *)&zeropage_calls);
+ if ( zero_list )
+ {
+ /* atomically remove this page from the list */
+ asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
+ " lwz %0,0(%1)\n" /* get next -- new zero_list */
+ " stwcx. %0,0,%2\n" /* update zero_list */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list), "=&r" (page)
+ : "r" (&zero_list)
+ : "cc" );
+ /* we can update zerocount after the fact since it is not
+ * used for anything but control of a loop which doesn't
+ * matter since it won't effect anything if it zero's one
+ * less page -- Cort
+ */
+ atomic_inc((atomic_t *)&zeropage_hits);
+ atomic_dec((atomic_t *)&zerocount);
+ wake_up(&page_zerod_wait);
+ resched_force();
+
+ /* zero out the pointer to next in the page */
+ *(unsigned long *)page = 0;
+ return page;
+ }
+ return 0;
+}
+
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+
+int zero_paged(void *unused)
+{
+ extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ sprintf(current->comm, "zero_paged (idle)");
+ current->blocked = ~0UL;
+
+ printk("Started zero_paged\n");
+
+ __sti();
+ while ( 1 )
+ {
+ /* don't want to be pre-empted by swapper or power_saved */
+ current->priority = -98;
+ current->counter = -98;
+ /* we don't want to run until we have something to do */
+ while ( zerocount >= PAGE_THRESHOLD )
+ sleep_on(&page_zerod_wait);
+ /*
+ * Mark a page as reserved so we can mess with it
+ * If we're interrupted we keep this page and our place in it
+ * since we validly hold it and it's reserved for us.
+ */
+ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ if ( !pageptr )
+ {
+ printk("!pageptr in zero_paged\n");
+ goto retry;
+ }
+
+ if ( resched_needed() )
+ schedule();
+
+ /*
+ * Make the page no cache so we don't blow our cache with 0's
+ */
+ dir = pgd_offset( init_task.mm, pageptr );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, pageptr & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ }
+ }
+ }
+
+ /*
+ * Important here to not take time away from real processes.
+ */
+ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+ {
+ if ( resched_needed() )
+ schedule();
+ *(unsigned long *)(bytecount + pageptr) = 0;
+ }
+
+ /*
+ * If we finished zero-ing out a page add this page to
+ * the zero_list atomically -- we can't use
+ * down/up since we can't sleep in idle.
+ * Disabling interrupts is also a bad idea since we would
+ * steal time away from real processes.
+ * We can also have several zero_paged's running
+ * on different processors so we can't interfere with them.
+ * So we update the list atomically without locking it.
+ * -- Cort
+ */
+ /* turn cache on for this page */
+ pte_cache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+
+ /* atomically add this page to the list */
+ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
+ " stw %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+ " sync\n" /* let store settle */
+#endif
+ " mr %0,%2\n" /* update zero_list in reg */
+ " stwcx. %2,0,%1\n" /* update zero_list in mem */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list)
+ : "r" (&zero_list), "r" (pageptr)
+ : "cc" );
+ /*
+ * This variable is used in the above loop and nowhere
+ * else so the worst that could happen is we would
+ * zero out one more or one less page than we want
+ * per processor on the machine. This is because
+ * we could add our page to the list but not have
+ * zerocount updated yet when another processor
+ * reads it. -- Cort
+ */
+ atomic_inc((atomic_t *)&zerocount);
+ atomic_inc((atomic_t *)&zerototal);
+retry:
+ schedule();
+ }
+}
+
+int power_saved(void *unused)
+{
+ unsigned long msr, hid0;
+ sprintf(current->comm, "power_saved (idle)");
+ current->blocked = ~0UL;
+
+ printk("Power saving daemon started\n");
+
+ __sti();
+ while (1)
+ {
+ /* don't want to be pre-empted by swapper */
+ current->priority = -99;
+ current->counter = -99;
+ /* go ahead and wakeup page_zerod() */
+ wake_up(&page_zerod_wait);
+ schedule();
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
+ /*
+ * The ibm carolina spec says that the eagle memory
+ * controller will detect the need for a snoop
+ * and wake up the processor so we don't need to
+ * check for cache operations that need to be
+ * snooped. The ppc book says the run signal
+ * must be asserted while napping for this though.
+ *
+ * Paul, what do you know about the pmac here?
+ * -- Cort
+ */
+ schedule();
+ }
+}
+
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 171bfaa5c..da3c53697 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,13 +1,13 @@
/*
* arch/ppc/kernel/irq.c
*
- * Power Macintosh version
- * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
* Derived from arch/i386/kernel/irq.c
* Copyright (C) 1992 Linus Torvalds
* Adapted from arch/i386 by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
@@ -15,11 +15,7 @@
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*/
-
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
+
#include <linux/ptrace.h>
#include <linux/errno.h>
@@ -30,121 +26,164 @@
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/config.h>
-
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/openpic.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/openpic.h>
+
+#include <asm/hydra.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-#define IRQ_FLAG ((unsigned *)0xf3000020)
-#define IRQ_ENABLE ((unsigned *)0xf3000024)
-#define IRQ_ACK ((unsigned *)0xf3000028)
-#define IRQ_LEVEL ((unsigned *)0xf300002c)
-
-#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
-
-#undef SHOW_IRQ 1
+#undef SHOW_IRQ
+#define OPENPIC_DEBUG
unsigned lost_interrupts = 0;
-
unsigned int local_irq_count[NR_CPUS];
-static struct irqaction irq_action[32];
+static struct irqaction irq_action[NR_IRQS];
+static int spurious_interrupts = 0;
+int __ppc_bh_counter;
+static unsigned int cached_irq_mask = 0xffffffff;
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+#define cached_21 (((char *)(&cached_irq_mask))[3])
+#define cached_A1 (((char *)(&cached_irq_mask))[2])
/*
- * This contains the irq mask for both irq controllers
+ * These are set to the appropriate functions by init_IRQ()
*/
-static unsigned int cached_irq_mask = 0xffff;
+void (*mask_and_ack_irq)(int irq_nr);
+void (*set_irq_mask)(int irq_nr);
-#define cached_21 (((char *)(&cached_irq_mask))[0])
-#define cached_A1 (((char *)(&cached_irq_mask))[1])
+/* prep */
+#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
+extern unsigned long route_pci_interrupts(void);
-int __ppc_bh_counter;
+/* pmac */
+#define IRQ_FLAG ((unsigned *)0xf3000020)
+#define IRQ_ENABLE ((unsigned *)0xf3000024)
+#define IRQ_ACK ((unsigned *)0xf3000028)
+#define IRQ_LEVEL ((unsigned *)0xf300002c)
+#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
+#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
-void *null_handler(int,void *,struct pt_regs *);
+/* chrp */
+volatile struct Hydra *Hydra = NULL;
-/*
- * disable and enable intrs in software. This is used
- * from the non-realtime parts of Linux to disable interrupts.
- * The realtime part disables/enables intrs in the hardware.
- * -- Cort
- */
-unsigned long soft_intr_enable = 1;
-void _soft_cli(void)
+void i8259_mask_and_ack_irq(int irq_nr)
{
- soft_intr_enable = 0;
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ if (irq_nr > 7) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x62,0x20); /* Specific EOI to cascade */
+ /*outb(0x20,0xA0);*/
+ outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
+ } else {
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
+ /*outb(0x20,0x20);*/
+ outb(0x60|irq_nr,0x20); /* specific eoi */
+
+ }
+ spin_unlock(&irq_controller_lock);
}
-void _soft_sti(void)
+void pmac_mask_and_ack_irq(int irq_nr)
{
- soft_intr_enable = 1;
- if ( lost_interrupts )
- {
- printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
- fake_interrupt();
- }
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+ out_le32(IRQ_ACK, 1U << irq_nr);
+ spin_unlock(&irq_controller_lock);
}
-void *
-null_handler(int a, void *b, struct pt_regs *regs)
+void chrp_mask_and_ack_irq(int irq_nr)
{
- /*printk("irq.c: null_handler() called. Should not have happened.\n");*/
+ /* spinlocks are done by i8259_mask_and_ack() - Cort */
+ if (is_8259_irq(irq_nr))
+ i8259_mask_and_ack_irq(irq_nr);
+ openpic_eoi(0);
}
-void
-disable_irq(unsigned int irq_nr)
-{
- int s = _disable_interrupts();
- unsigned char mask;
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-#else /* CONFIG_PMAC */
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8)
- {
- cached_21 |= mask;
- outb(cached_21,0x21);
- } else
- {
- cached_A1 |= mask;
+void i8259_set_irq_mask(int irq_nr)
+{
+ if (irq_nr > 7) {
outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
- _enable_interrupts(s);
+ } else {
+ outb(cached_21,0x21);
+ }
}
-void
-enable_irq(unsigned int irq_nr)
+void pmac_set_irq_mask(int irq_nr)
{
- int s = _disable_interrupts();
-#ifdef CONFIG_PMAC
- unsigned bit = 1U << irq_nr;
-
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
-
+ /* this could be being enabled or disabled - so use cached_irq_mask */
+ out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
/*
* Unfortunately, setting the bit in the enable register
* when the device interrupt is already on *doesn't* set
* the bit in the flag register or request another interrupt.
*/
- if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
- lost_interrupts |= bit;
-#else /* CONFIG_PMAC */
- if (irq_nr < 8) {
- cached_21 &= ~(1 << (irq_nr & 7));
- outb(cached_21,0x21);
+ if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
+ lost_interrupts |= (1UL<<irq_nr);
+}
+
+void chrp_set_irq_mask(int irq_nr)
+{
+ if (is_8259_irq(irq_nr)) {
+ i8259_set_irq_mask(irq_nr);
} else
{
- cached_A1 &= ~(1 << (irq_nr-8 & 7));
- outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
+ /* disable? */
+ if ( cached_irq_mask & (1UL<<irq_nr) )
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ /* enable */
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ }
+}
+
+/*
+ * 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);
+}
- _enable_interrupts(s);
+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;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ mask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+ synchronize_irq();
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ unmask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
int get_irq_list(char *buf)
{
@@ -153,7 +192,7 @@ int get_irq_list(char *buf)
for (i = 0 ; i < NR_IRQS ; i++) {
action = irq_action + i;
- if (!action || !action->handler)
+ if (!action || !action->handler)
continue;
len += sprintf(buf+len, "%2d: %10u %s",
i, kstat.interrupts[i], action->name);
@@ -162,152 +201,143 @@ int get_irq_list(char *buf)
}
len += sprintf(buf+len, "\n");
}
-/*
- * Linus - should you add NMI counts here ?????
- */
#ifdef __SMP_PROF__
len+=sprintf(buf+len, "IPI: %8lu received\n",
ipi_count);
-#endif
+#endif
+ len += sprintf(buf+len, "99: %10u spurious or short\n",
+ spurious_interrupts);
return len;
}
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs)
{
int irq;
- unsigned bits;
+ unsigned long bits;
struct irqaction *action;
int cpu = smp_processor_id();
+ int status;
hardirq_enter(cpu);
-#ifdef CONFIG_PMAC
- bits = ld_le32(IRQ_FLAG) | lost_interrupts;
- lost_interrupts = 0;
-
- for (irq = NR_IRQS; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-#else /* CONFIG_PMAC */
-#if 1
- if ( lost_interrupts )
- {
- irq = ffz(~lost_interrupts);
- lost_interrupts &= ~irq;
- goto retry;
- }
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
+
+ /*
+ * I'll put this ugly mess of code into a function
+ * such as get_pending_irq() or some such clear thing
+ * so we don't have a switch in the irq code and
+ * the chrp code is merged a bit with the prep.
+ * -- Cort
+ */
+ switch ( _machine )
{
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
+ case _MACH_Pmac:
+ bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+ lost_interrupts = 0;
+ for (irq = NR_IRQS - 1; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
+ break;
+ case _MACH_chrp:
+ irq = openpic_irq(0);
+ if (irq == IRQ_8259_CASCADE)
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ irq = (*(volatile unsigned char *)0xfec80000) & 0x0f;
+ }
+ else if (irq >= 64)
+ {
+ /*
+ * OpenPIC interrupts >64 will be used for other purposes
+ * like interprocessor interrupts and hardware errors
+ */
+#ifdef OPENPIC_DEBUG
+ printk("OpenPIC interrupt %d\n", irq);
+#endif
+ if (irq==99)
+ spurious_interrupts++;
+ }
+ else {
+ /*
+ * Here we should process IPI timer
+ * for now the interrupt is dismissed.
+ */
goto out;
- irq = (irq&7) + 8;
- }
-retry:
+ }
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+#if 1
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+retry_cascade:
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ /* if no intr left */
+ if ( !(irq & 128 ) )
+ goto out;
+ irq = (irq&7) + 8;
+ }
+ bits = 1UL << irq;
#else
- /* get the irr from the intr controller */
- outb(0x0A, 0x20);
- bits = inb(0x20);
- /* handle cascade */
- if ( bits )
- {
- bits &= 4;
- outb(0x0A, 0xA0);
- bits = inb(0xA0)<<8;
+ /*
+ * get the isr from the intr controller since
+ * the bit in the irr has been cleared
+ */
+ outb(0x0a, 0x20);
+ bits = inb(0x20)&0xff;
+ /* handle cascade */
+ if ( bits & 4 )
+ {
+ bits &= ~4UL;
+ outb(0x0a, 0xA0);
+ bits |= inb(0xA0)<<8;
+ }
+ /* ignore masked irqs */
+ bits &= ~cached_irq_mask;
+#endif
+ break;
}
- /* get lost interrupts */
- bits |= lost_interrupts;
- /* save intrs that are masked out */
- lost_interrupts = bits & cached_irq_mask;
- /* get rid of intrs being masked */
- bits &= ~cached_irq_mask;
- /* non-specifc eoi */
- outb(0x20,0x20);
- if ( bits & 0xff00 )
- outb(0x20,0xA0);
-
- printk("bits %04X lost %04X mask %04x\n",
- bits, lost_interrupts,cached_irq_mask);
-
- for (irq = NR_IRQS; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-#endif
-#endif /* CONFIG_PMAC */
if (irq < 0) {
- printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+ printk("Bogus interrupt from PC = %lx\n", regs->nip);
goto out;
}
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ACK, 1U << irq);
-#else /* CONFIG_PMAC */
- /* mask out the irq while handling it */
- disable_irq(irq);
- /*
- * send eoi to interrupt controller right away or lower
- * priority intrs would be ignored even if with intrs enabled
- */
- if (irq > 7)
- {
- outb(0xE0|(irq-8), 0xA0);
- outb(0xE2, 0x20);
- } else
- {
- outb(0xE0|irq, 0x20);
- }
-#endif /* !CONFIG_PMAC */
+ mask_and_ack_irq(irq);
- /*
- * now that we've acked the irq, if intrs are disabled in software
- * we're in the real-time system and non-rt linux has disabled them
- * so we just queue it up and return -- Cort
- */
- if ( ! soft_intr_enable )
- {
- lost_interrupts |= 1UL << irq;
- /* can't printk - kernel expects intrs off! */
- /*printk("irq %d while intrs soft disabled\n", irq);*/
- goto out;
- }
-
- action = irq + irq_action;
+ status = 0;
+ action = irq_action + irq;
kstat.interrupts[irq]++;
- if (action->handler) {
- action->handler(irq, action->dev_id, regs);
- _disable_interrupts(); /* in case the handler turned them on */
+ if ( action && action->handler)
+ {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ /*if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);*/
+ __cli(); /* in case the handler turned them on */
+ spin_lock(&irq_controller_lock);
+ unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
} else {
+ if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
+ spurious_interrupts++;
disable_irq( irq );
}
-#ifdef CONFIG_PREP
- /* re-enable if the interrupt was good and isn't one-shot */
- if ( action->handler && !(action->flags & SA_ONESHOT) )
- enable_irq(irq);
+
/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
- if ( irq > 7 )
+ if ( is_prep && (irq > 7) )
goto retry_cascade;
-#endif
-
- hardirq_exit(cpu);
- /*
- * 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();
- return;
+ /* do_bottom_half is called if necessary from int_return in head.S */
out:
hardirq_exit(cpu);
-
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -315,13 +345,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
{
struct irqaction * action;
unsigned long flags;
-
-#ifdef SHOW_IRQ
+
+#ifdef SHOW_IRQ
printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
irq,handler,devname,dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS)
+
+ if (irq >= NR_IRQS)
return -EINVAL;
action = irq + irq_action;
if (action->handler)
@@ -339,17 +369,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
restore_flags(flags);
return 0;
}
-
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action = irq + irq_action;
unsigned long flags;
-#ifdef SHOW_IRQ
+#ifdef SHOW_IRQ
printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS) {
+
+ if (irq >= NR_IRQS) {
printk("Trying to free IRQ%d\n",irq);
return;
}
@@ -370,114 +399,119 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
- unsigned long delay;
-
- /* first, snaffle up any unassigned irqs */
- for (i = 15; i > 0; i--) {
- if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
- enable_irq(i);
- irqs |= (1 << i);
- }
- }
-
- /* wait for spurious interrupts to mask themselves out again */
- for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
-
- /* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i) & irqmask) {
- irqs ^= (1 << i);
- free_irq(i, NULL);
- }
- }
-#ifdef DEBUG
- printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- return irqs;
+ return 0;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
-
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i)) {
- free_irq(i, NULL);
- }
- }
-#ifdef SHOW_IRQ
- printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- irqs &= irqmask;
- if (!irqs)
- return 0;
- i = ffz(~irqs);
- if (irqs != (irqs & (1 << i)))
- i = -i;
- return i;
+ return 0;
}
-void init_IRQ(void)
+__initfunc(static void i8259_init(void))
{
-#ifdef CONFIG_PMAC
- extern void xmon_irq(int, void *, struct pt_regs *);
-
- *IRQ_ENABLE = 0;
- request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
-#else /* CONFIG_PMAC */
- /* Initialize interrupt controllers */
+ /* init master interrupt controller */
outb(0x11, 0x20); /* Start init sequence */
outb(0x40, 0x21); /* Vector base */
-#if 1
- outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-#else
+ /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
-
outb(0x01, 0x21); /* Select 8086 mode */
outb(0xFF, 0x21); /* Mask all */
-
+
+ /* init slave interrupt controller */
outb(0x11, 0xA0); /* Start init sequence */
outb(0x48, 0xA1); /* Vector base */
-#if 1
- outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-#else
+ /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
outb(0x01, 0xA1); /* Select 8086 mode */
outb(0xFF, 0xA1); /* Mask all */
-
- /*
- * Program level mode for irq's that 'can' be level triggered.
- * This does not effect irq's 0,1,2 and 8 since they must be
- * edge triggered. This is not the PIC controller. The default
- * here is for edge trigger mode. -- Cort
- */
-#if 0
- outb(0xf8, 0x4d0); /* level triggered */
- outb(0xff, 0x4d1);
-#endif
-#if 0
- outb(0x00, 0x4D0); /* All edge triggered */
- outb(0xCF, 0x4D1); /* Trigger mode */
-#endif
outb(cached_A1, 0xA1);
outb(cached_21, 0x21);
- if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+ panic("Could not allocate cascade IRQ!");
enable_irq(2); /* Enable cascade interrupt */
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set timer to periodic mode */
- outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
- /* set the clock to ~100 Hz */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
-
- route_pci_interrupts();
-#endif /* CONFIG_PMAC */
+}
+
+__initfunc(void init_IRQ(void))
+{
+ extern void xmon_irq(int, void *, struct pt_regs *);
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ mask_and_ack_irq = pmac_mask_and_ack_irq;
+ set_irq_mask = pmac_set_irq_mask;
+
+ *IRQ_ENABLE = 0;
+#ifdef CONFIG_XMON
+ request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ mask_and_ack_irq = i8259_mask_and_ack_irq;
+ set_irq_mask = i8259_set_irq_mask;
+
+ i8259_init();
+ route_pci_interrupts();
+ /*
+ * According to the Carolina spec from ibm irq's 0,1,2, and 8
+ * must be edge triggered. Also, the pci intrs must be level
+ * triggered and _only_ isa intrs can be level sensitive
+ * which are 3-7,9-12,14-15. 13 is special - it can be level.
+ *
+ * power on default is 0's in both regs - all edge.
+ *
+ * These edge/level control regs allow edge/level status
+ * to be decided on a irq basis instead of on a PIC basis.
+ * It's still pretty ugly.
+ * - Cort
+ */
+ {
+ unsigned char irq_mode1 = 0, irq_mode2 = 0;
+ irq_mode1 = 0; /* to get rid of compiler warnings */
+ /*
+ * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
+ */
+ if ( _machine == _MACH_IBM )
+ irq_mode2 |= 0xa0;
+ /*
+ * Sound on the Powerstack reportedly needs to be edge triggered
+ */
+ if ( _machine == _MACH_Motorola )
+ {
+ /*irq_mode2 &= ~0x04L;
+ outb( irq_mode1 , 0x4d0 );
+ outb( irq_mode2 , 0x4d1 );*/
+ }
+
+ }
+ break;
+ case _MACH_chrp:
+ mask_and_ack_irq = chrp_mask_and_ack_irq;
+ set_irq_mask = chrp_set_irq_mask;
+ if ((Hydra = find_hydra())) {
+ printk("Hydra Mac I/O at %p\n", Hydra);
+ out_le32(&Hydra->Feature_Control, HYDRA_FC_SCC_CELL_EN |
+ HYDRA_FC_SCSI_CELL_EN |
+ HYDRA_FC_SCCA_ENABLE |
+ HYDRA_FC_SCCB_ENABLE |
+ HYDRA_FC_ARB_BYPASS |
+ HYDRA_FC_MPIC_ENABLE |
+ HYDRA_FC_SLOW_SCC_PCLK |
+ HYDRA_FC_MPIC_IS_MASTER);
+ OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC;
+ } else if (!OpenPIC /* && find_xxx */) {
+ printk("Unknown openpic implementation\n");
+ /* other OpenPIC implementations */
+ /* ... */
+ }
+ if (OpenPIC)
+ openpic_init();
+ else
+ panic("No OpenPIC found");
+ if (Hydra)
+ hydra_post_openpic_init();
+ i8259_init();
+ break;
+ }
}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 430cd7a5d..9c6d013b6 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -64,6 +64,7 @@ _GLOBAL(_hard_sti)
mtmsr r3 /* Update machine state */
blr
+#if 0
/*
* Restore 'flags'
* __restore_flags(long val)
@@ -79,11 +80,13 @@ _GLOBAL(__restore_flags)
mtmsr r3
isync
blr
-
+#endif
+
/*
* We were about to enable interrupts but we have to simulate
* some interrupts that were lost by enable_irq first.
*/
+ .globl do_lost_interrupts
do_lost_interrupts:
stwu r1,-16(r1)
mflr r0
@@ -243,7 +246,6 @@ _GLOBAL(_outsl)
bdnz 00b
blr
-#ifdef CONFIG_PMAC
_GLOBAL(ide_insw)
mtctr r5
subi r4,r4,2
@@ -259,7 +261,6 @@ _GLOBAL(ide_outsw)
sthx r5,0,r3
bdnz 00b
blr
-#endif
/*
* Extended precision shifts
@@ -298,7 +299,7 @@ _GLOBAL(abs)
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
-
+
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
@@ -308,6 +309,7 @@ cvt_fd:
lfs 0,0(r3)
stfd 0,0(r4)
blr
+
/*
* Fetch the current SR register
* get_SR(int index)
@@ -317,7 +319,6 @@ _GLOBAL(get_SR)
mr r3,r4
blr
-
_GLOBAL(cvt_df)
cvt_df:
lfd 0,0(r3)
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 3f404a37a..80f10c59e 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -29,7 +29,6 @@
void
main(void)
{
- /*DEFINE(KERNELBASE, KERNELBASE);*/
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -37,54 +36,20 @@ main(void)
DEFINE(SIGNAL, offsetof(struct task_struct, signal));
DEFINE(TSS, offsetof(struct task_struct, tss));
DEFINE(KSP, offsetof(struct thread_struct, ksp));
- DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
-#ifdef CONFIG_PMAC
- DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
- DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
-#endif
+ /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
+ DEFINE(MM, offsetof(struct task_struct, mm));
+ DEFINE(PGD, offsetof(struct mm_struct, pgd));
DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(PF_TRACESYS, PF_TRACESYS);
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
-#if 0
- DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
- DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
- DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
- DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
- DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
- DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
- DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
- DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
- DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
- DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
- DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
- DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
- DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
- DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
- DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
- DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
- DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
- DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
- DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
- DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
- DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
- DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
- DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
- DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
- DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
- DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
- DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
- DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
- DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
- DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
- DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
-#endif
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+ /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c
new file mode 100644
index 000000000..7eb5e5aa9
--- /dev/null
+++ b/arch/ppc/kernel/openpic.c
@@ -0,0 +1,546 @@
+/*
+ * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+
+/*
+ * Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
+ */
+
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/openpic.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+#define REGISTER_DEBUG
+#undef REGISTER_DEBUG
+
+
+#define VEC_TIMER 0x40 /* and up */
+#define VEC_IPI 0x50 /* and up */
+#define VEC_SOURCE 0x10 /* and up */
+#define VEC_SPURIOUS 99
+
+
+volatile struct OpenPIC *OpenPIC;
+
+static u_int Version;
+static u_int NumProcessors;
+static u_int NumSources;
+static u_int VendorID;
+static u_int DeviceID;
+static u_int Stepping;
+static u_int TimerFrequency;
+
+
+ /*
+ * Accesses to the current processor's registers
+ */
+
+#ifndef __powerpc__
+#define THIS_CPU Private
+#define CHECK_THIS_CPU do {} while (0)
+#else
+#define THIS_CPU Processor[cpu]
+#define CHECK_THIS_CPU check_arg_cpu(cpu)
+#endif
+
+
+ /*
+ * Sanity checks
+ */
+
+#if 1
+#define check_arg_ipi(ipi) \
+ if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
+ printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi);
+#define check_arg_timer(timer) \
+ if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
+ printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer);
+#define check_arg_vec(vec) \
+ if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
+ printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec);
+#define check_arg_pri(pri) \
+ if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
+ printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
+#define check_arg_irq(irq) \
+ if (irq < 0 || irq >= NumSources) \
+ printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);
+#define check_arg_cpu(cpu) \
+ if (cpu < 0 || cpu >= NumProcessors) \
+ printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
+#else
+#define check_arg_ipi(ipi) do {} while (0)
+#define check_arg_timer(timer) do {} while (0)
+#define check_arg_vec(vec) do {} while (0)
+#define check_arg_pri(pri) do {} while (0)
+#define check_arg_irq(irq) do {} while (0)
+#define check_arg_cpu(cpu) do {} while (0)
+#endif
+
+
+ /*
+ * Dummy interrupt handler
+ */
+
+static void no_action(int ir1, void *dev, struct pt_regs *regs)
+{}
+
+
+ /*
+ * I/O functions
+ */
+
+#ifdef __i386__
+static inline u_int ld_le32(volatile u_int *addr)
+{
+ return *addr;
+}
+
+static inline void out_le32(volatile u_int *addr, u_int val)
+{
+ *addr = val;
+}
+#endif
+
+static inline u_int openpic_read(volatile u_int *addr)
+{
+ u_int val;
+
+ val = ld_le32(addr);
+#ifdef REGISTER_DEBUG
+ printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
+#endif
+ return val;
+}
+
+static inline void openpic_write(volatile u_int *addr, u_int val)
+{
+#ifdef REGISTER_DEBUG
+ printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val);
+#endif
+ out_le32(addr, val);
+}
+
+
+static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
+{
+ u_int val = openpic_read(addr);
+ return val & mask;
+}
+
+static inline void openpic_writefield(volatile u_int *addr, u_int mask,
+ u_int field)
+{
+ u_int val = openpic_read(addr);
+ openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
+{
+ openpic_writefield(addr, mask, 0);
+}
+
+static inline void openpic_setfield(volatile u_int *addr, u_int mask)
+{
+ openpic_writefield(addr, mask, mask);
+}
+
+
+ /*
+ * Update a Vector/Priority register in a safe manner. The interrupt will
+ * be disabled.
+ */
+
+static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
+ u_int field)
+{
+ openpic_setfield(addr, OPENPIC_MASK);
+ /* wait until it's not in use */
+ while (openpic_read(addr) & OPENPIC_ACTIVITY);
+ openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+
+/* -------- Global Operations ---------------------------------------------- */
+
+
+ /*
+ * Initialize the OpenPIC
+ */
+
+void openpic_init(void)
+{
+ u_int t, i;
+ const char *version, *vendor, *device;
+
+ if (!OpenPIC) {
+ printk("No OpenPIC present\n");
+ return;
+ }
+
+ t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+ Version = t & OPENPIC_FEATURE_VERSION_MASK;
+ NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+ OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+ NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+ OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+
+ switch (Version) {
+ case 1:
+ version = "1.0";
+ break;
+ case 2:
+ version = "1.2";
+ break;
+ default:
+ version = "?.?";
+ break;
+ }
+ printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
+ NumProcessors, NumSources, OpenPIC);
+
+ t = openpic_read(&OpenPIC->Global.Vendor_Identification);
+ VendorID = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
+ DeviceID = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
+ OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
+ Stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
+ OPENPIC_VENDOR_ID_STEPPING_SHIFT;
+ switch (VendorID) {
+ case OPENPIC_VENDOR_ID_APPLE:
+ vendor = "Apple";
+ break;
+ default:
+ vendor = "Unknown";
+ break;
+ }
+ switch (DeviceID) {
+ case OPENPIC_DEVICE_ID_APPLE_HYDRA:
+ device = "Hydra";
+ break;
+ default:
+ device = "Unknown";
+ break;
+ }
+ printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", VendorID,
+ vendor, DeviceID, device, Stepping);
+
+ TimerFrequency = openpic_read(&OpenPIC->Global.Timer_Frequency);
+ printk("OpenPIC timer frequency is ");
+ if (TimerFrequency)
+ printk("%d Hz\n", TimerFrequency);
+ else
+ printk("not set\n");
+
+ /* Initialize timer interrupts */
+ for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+ /* Disabled, Priority 0 */
+ openpic_inittimer(i, 0, VEC_TIMER+i);
+ /* No processor */
+ openpic_maptimer(i, 0);
+ }
+
+ /* Initialize IPI interrupts */
+ for (i = 0; i < OPENPIC_NUM_IPI; i++) {
+ /* Disabled, Priority 0 */
+ openpic_initipi(i, 0, VEC_IPI+i);
+ }
+
+ /* Initialize external interrupts */
+ /* SIOint (8259 cascade) is special */
+ openpic_initirq(0, 8, VEC_SOURCE, 1, 1); /* 0,1 gives interrupt storm */
+ /* Processor 0 */
+ openpic_mapirq(0, 1<<0);
+ for (i = 1; i < NumSources; i++) {
+ /* Enabled, Priority 8 */
+ openpic_initirq(i, 8, VEC_SOURCE+i, 0, 1);
+ /* Processor 0 */
+ openpic_mapirq(i, 1<<0);
+ }
+
+ /* Initialize the spurious interrupt */
+ openpic_set_spurious(VEC_SPURIOUS);
+
+ if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
+ "OpenPIC cascade", NULL))
+ printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+ openpic_set_priority(0, 0);
+ openpic_disable_8259_pass_through();
+}
+
+
+ /*
+ * Reset the OpenPIC
+ */
+
+void openpic_reset(void)
+{
+ openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_RESET);
+}
+
+
+ /*
+ * Enable/disable 8259 Pass Through Mode
+ */
+
+void openpic_enable_8259_pass_through(void)
+{
+ openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+void openpic_disable_8259_pass_through(void)
+{
+ openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+
+#ifndef __i386__
+ /*
+ * Find out the current interrupt
+ */
+
+u_int openpic_irq(u_int cpu)
+{
+ u_int vec;
+
+ check_arg_cpu(cpu);
+ vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
+ OPENPIC_VECTOR_MASK);
+#if 0
+if (vec != 22 /* SCSI */)
+printk("++openpic_irq: %d\n", vec);
+#endif
+ return vec;
+}
+#endif
+
+
+ /*
+ * Signal end of interrupt (EOI) processing
+ */
+
+#ifndef __powerpc__
+void openpic_eoi(void)
+#else
+void openpic_eoi(u_int cpu)
+#endif
+{
+#if 0
+printk("++openpic_eoi:\n");
+#endif
+ check_arg_cpu(cpu);
+ openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+}
+
+
+ /*
+ * Get/set the current task priority
+ */
+
+#ifndef __powerpc__
+u_int openpic_get_priority(void)
+#else
+u_int openpic_get_priority(u_int cpu)
+#endif
+{
+ CHECK_THIS_CPU;
+ return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+ OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+}
+
+#ifndef __powerpc__
+void openpic_set_priority(u_int pri)
+#else
+void openpic_set_priority(u_int cpu, u_int pri)
+#endif
+{
+ CHECK_THIS_CPU;
+ check_arg_pri(pri);
+ openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+ OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+ /*
+ * Get/set the spurious vector
+ */
+
+u_int openpic_get_spurious(void)
+{
+ return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
+ OPENPIC_VECTOR_MASK);
+}
+
+void openpic_set_spurious(u_int vec)
+{
+ check_arg_vec(vec);
+ openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+ vec);
+}
+
+
+ /*
+ * Initialize one or more CPUs
+ */
+
+void openpic_init_processor(u_int cpumask)
+{
+ openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
+}
+
+
+/* -------- Interprocessor Interrupts -------------------------------------- */
+
+
+ /*
+ * Initialize an interprocessor interrupt (and disable it)
+ *
+ * ipi: OpenPIC interprocessor interrupt number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ */
+
+void openpic_initipi(u_int ipi, u_int pri, u_int vec)
+{
+ check_arg_timer(ipi);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+
+ /*
+ * Send an IPI to one or more CPUs
+ */
+
+#ifndef __powerpc__
+void openpic_cause_IPI(u_int ipi, u_int cpumask)
+#else
+void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask)
+#endif
+{
+ CHECK_THIS_CPU;
+ check_arg_ipi(ipi);
+ openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
+}
+
+
+/* -------- Timer Interrupts ----------------------------------------------- */
+
+
+ /*
+ * Initialize a timer interrupt (and disable it)
+ *
+ * timer: OpenPIC timer number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ */
+
+void openpic_inittimer(u_int timer, u_int pri, u_int vec)
+{
+ check_arg_timer(timer);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+
+ /*
+ * Map a timer interrupt to one or more CPUs
+ */
+
+void openpic_maptimer(u_int timer, u_int cpumask)
+{
+ check_arg_timer(timer);
+ openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
+}
+
+
+/* -------- Interrupt Sources ---------------------------------------------- */
+
+
+ /*
+ * Enable/disable an interrupt source
+ */
+
+void openpic_enable_irq(u_int irq)
+{
+ check_arg_irq(irq);
+ openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+}
+
+void openpic_disable_irq(u_int irq)
+{
+ check_arg_irq(irq);
+ openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+}
+
+
+ /*
+ * Initialize an interrupt source (and disable it!)
+ *
+ * irq: OpenPIC interrupt number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ * pol: polarity (1 for positive, 0 for negative)
+ * sense: 1 for level, 0 for edge
+ */
+
+void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+ check_arg_irq(irq);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+ OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec |
+ (pol ? OPENPIC_SENSE_POLARITY : 0) |
+ (sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+
+ /*
+ * Map an interrupt source to one or more CPUs
+ */
+
+void openpic_mapirq(u_int irq, u_int cpumask)
+{
+ check_arg_irq(irq);
+ openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
+}
+
+
+ /*
+ * Set the sense for an interrupt source (and disable it!)
+ *
+ * sense: 1 for level, 0 for edge
+ */
+
+void openpic_set_sense(u_int irq, int sense)
+{
+ check_arg_irq(irq);
+ openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_SENSE_LEVEL,
+ (sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+
diff --git a/arch/ppc/kernel/pci-bridge.c b/arch/ppc/kernel/pci-bridge.c
new file mode 100644
index 000000000..0e4420340
--- /dev/null
+++ b/arch/ppc/kernel/pci-bridge.c
@@ -0,0 +1,428 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+ void *io_base;
+ int bus_number;
+ int max_bus;
+ struct bridge_data *next;
+ struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID 0x106b
+#define BANDIT_DEVID 1
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+ if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the revision id */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+ rev, bp->io_base);
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32((volatile unsigned int *)bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+ bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+ int bus;
+ struct bridge_data *bridge;
+
+ bridge_list = 0;
+ max_bus = 0;
+ add_bridges(find_devices("bandit"), &mem_start);
+ add_bridges(find_devices("chaos"), &mem_start);
+ bridges = (struct bridge_data **) mem_start;
+ mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+ memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+ for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+ for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+ bridges[bus] = bridge;
+
+ return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+ int *bus_range;
+ int len;
+ struct bridge_data *bp;
+
+ for (; dev != NULL; dev = dev->next) {
+ if (dev->n_addrs < 1) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+ bus_range[1]);
+ printk(" controlled by %s at %x\n",
+ dev->name, dev->addrs[0].address);
+ bp = (struct bridge_data *) *mem_ptr;
+ *mem_ptr += sizeof(struct bridge_data);
+ bp->cfg_addr = (volatile unsigned int *)
+ (dev->addrs[0].address + 0x800000);
+ bp->cfg_data = (volatile unsigned char *)
+ (dev->addrs[0].address + 0xc00000);
+ bp->io_base = (void *) dev->addrs[0].address;
+ ioremap(dev->addrs[0].address, 0x800000);
+ bp->bus_number = bus_range[0];
+ bp->max_bus = bus_range[1];
+ bp->next = bridge_list;
+ bp->node = dev;
+ bridge_list = bp;
+ if (bp->max_bus > max_bus)
+ max_bus = bp->max_bus;
+
+ if (strcmp(dev->name, "bandit") == 0)
+ init_bandit(bp);
+ }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr)
+{
+ unsigned int *reg;
+ int len;
+
+ reg = (unsigned int *) get_property(dev, "reg", &len);
+ if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+ /* doesn't look like a PCI device */
+ *bus_ptr = 0xff;
+ *devfn_ptr = 0xff;
+ return -1;
+ }
+ *bus_ptr = reg[0] >> 16;
+ *devfn_ptr = reg[0] >> 8;
+ return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_8(bp->cfg_data + (offset & 3));
+
+ if (offset == PCI_INTERRUPT_LINE) {
+ /*
+ * Open Firmware often doesn't initialize this
+ * register properly, so we find the node and see
+ * if it has an AAPL,interrupts property.
+ */
+ struct device_node *node;
+ unsigned int *reg;
+
+ for (node = bp->node->child; node != 0; node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ *val = node->intrs[0];
+ break;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffffffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ *val = in_le32((volatile unsigned int *)bp->cfg_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_8(bp->cfg_data + (offset & 3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x, vendev;
+ unsigned char h;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_VENDOR_ID, &x)
+ == PCIBIOS_SUCCESSFUL && x == vendev) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x;
+ unsigned char h;
+
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_CLASS_REVISION, &x)
+ == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+ return 0;
+}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 612a24bff..49f2f37be 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,630 +1,194 @@
/*
- * PCI support
- * -- rough emulation of "PCI BIOS" functions
- *
- * Note: these are very motherboard specific! Some way needs to
- * be worked out to handle the differences.
+ * $Id: pci.c,v 1.12 1997/08/27 05:05:28 cort Exp $
+ * Common pmac/prep/chrp pci routines. -- Cort
*/
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/bios32.h>
+#include <linux/kernel.h>
#include <linux/pci.h>
+/*#include <linux/bios32.h>*/
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
-/*
- * PCI interrupt configuration. This is motherboard specific.
- */
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
-
-/* Tables for known hardware */
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Blackhawk_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Comet_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* BeBox */
-static char BeBox_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 16, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char BeBox_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* IBM Nobis */
-static char Nobis_pci_IRQ_map[16] =
-{
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 13, /* Line 1 */
- 13, /* Line 2 */
- 13, /* Line 3 */
- 13 /* Line 4 */
-};
-
+unsigned long io_base;
+unsigned long pci_dram_offset;
/*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
- */
-static char ibm8xx_pci_IRQ_map[23] = {
- 0, /* Slot 0 - unused */
- 0, /* Slot 1 - unused */
- 0, /* Slot 2 - unused */
- 0, /* Slot 3 - unused */
- 0, /* Slot 4 - unused */
- 0, /* Slot 5 - unused */
- 0, /* Slot 6 - unused */
- 0, /* Slot 7 - unused */
- 0, /* Slot 8 - unused */
- 0, /* Slot 9 - unused */
- 0, /* Slot 10 - unused */
- 0, /* Slot 11 - FireCoral */
- 4, /* Slot 12 - Ethernet PCIINTD# */
- 2, /* Slot 13 - PCI Slot #2 */
- 2, /* Slot 14 - S3 Video PCIINTD# */
- 0, /* Slot 15 - onboard SCSI (INDI) [1] */
- 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
- 0, /* Slot 17 - unused */
- 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
- 0, /* Slot 19 - unused */
- 0, /* Slot 20 - unused */
- 0, /* Slot 21 - unused */
- 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-static char ibm8xx_pci_IRQ_routes[] = {
- 0, /* Line 0 - unused */
- 13, /* Line 1 */
- 10, /* Line 2 */
- 15, /* Line 3 */
- 15, /* Line 4 */
-};
-/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
- * it really needs some logic to set them to unique IRQ's, or even
- * add some logic to the drivers to ask an irq.c routine to re-map
- * the IRQ if it needs one to itself...
+ * It would be nice if we could create a include/asm/pci.h and have just
+ * function ptrs for all these in there, but that isn't the case.
+ * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
+ * which has been setup by pcibios_init(). This is all to avoid a check
+ * for pmac/prep every time we call one of these. It should also make the move
+ * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
+ * and create pci.h
+ * -- Cort
*/
-static char Carolina_PIRQ_routes[] = {
- 0xad, /* INTB# = 10, INTA# = 13 */
- 0xff /* INTD# = 15, INTC# = 15 */
-};
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
-#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
-#define PCI_DEVICE_ID_IBM_CORAL 0x000a
-
-#undef PCI_DEBUG
-
-#ifdef PCI_STATS
-int PCI_conversions[2];
-#endif
-
-
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
-{
- return mem_start;
+int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_present (void)
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
{
-#ifdef PCI_DEBUG
- printk("PCI [BIOS] present?\n");
-#endif
- return (1);
+ return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int *val)
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config dword[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le32_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short *val)
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = (unsigned short)0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le16_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char *val)
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
{
- unsigned char _val;
- volatile unsigned char *ptr;
- dev >>= 3;
- /* Note: the configuration registers don't always have this right! */
- if (offset == PCI_INTERRUPT_LINE)
- {
- if (Motherboard_map[dev] <= 4)
- {
- *val = Motherboard_routes[Motherboard_map[dev]];
- /*printk("dev %d map %d route %d\n",
- dev,Motherboard_map[dev],
- Motherboard_routes[Motherboard_map[dev]]);*/
- } else
- { /* Pseudo interrupts [for BeBox] */
- *val = Motherboard_map[dev];
- }
-#ifdef PCI_DEBUG
- printk("PCI Read Interrupt Line[%d.%d] = %d\n", bus, dev, *val);
-#endif
- return PCIBIOS_SUCCESSFUL;
- }
-#ifdef PCI_DEBUG
- printk("PCI Read config byte[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = *ptr;
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int val)
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
- _val = le32_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short val)
+int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
- _val = le16_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
}
-
-int
-pcibios_write_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char val)
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
{
- unsigned char _val;
- unsigned char *ptr;
- dev >>= 3;
- _val = val;
-#ifdef PCI_DEBUG
- printk("PCI Write config byte[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
}
-int
-pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *dev)
+int pcibios_present(void)
{
- unsigned long w, desired = (device_id << 16) | vendor;
- int devnr;
-
- if (vendor == 0xffff) {
- return PCIBIOS_BAD_VENDOR_ID;
- }
-
- for (devnr = 11; devnr < 16; devnr++)
- {
- pcibios_read_config_dword(0, devnr<<3, PCI_VENDOR_ID, &w);
- if (w == desired) {
- if (index == 0) {
- *bus = 0;
- *dev = devnr<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- --index;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
+ return 1;
}
-int
-pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *dev)
-{
- int dev_nr, class, indx;
- indx = 0;
-#ifdef PCI_DEBUG
- printk("pcibios_find_class - class: %x, index: %x", class_code, index);
-#endif
- for (dev_nr = 11; dev_nr < 16; dev_nr++)
- {
- pcibios_read_config_dword(0, dev_nr<<3, PCI_CLASS_REVISION, &class);
- if ((class>>8) == class_code)
- {
- if (index == indx)
- {
- *bus = 0;
- *dev = dev_nr<<3;
-#ifdef PCI_DEBUG
- printk(" - device: %x\n", dev_nr);
-#endif
- return (0);
- }
- indx++;
- }
- }
-#ifdef PCI_DEBUG
- printk(" - not found\n");
-#endif
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-const char *pcibios_strerror(int error)
-{
- static char buf[32];
- switch (error)
- { case PCIBIOS_SUCCESSFUL:
- return ("PCI BIOS: no error");
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return ("PCI BIOS: function not supported");
- case PCIBIOS_BAD_VENDOR_ID:
- return ("PCI BIOS: bad vendor ID");
- case PCIBIOS_DEVICE_NOT_FOUND:
- return ("PCI BIOS: device not found");
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return ("PCI BIOS: bad register number");
- case PCIBIOS_SET_FAILED:
- return ("PCI BIOS: set failed");
- case PCIBIOS_BUFFER_TOO_SMALL:
- return ("PCI BIOS: buffer too small");
- default:
- sprintf(buf, "PCI BIOS: invalid error #%d", error);
- return(buf);
+__initfunc(unsigned long
+pcibios_init(unsigned long mem_start,unsigned long mem_end))
+{
+ switch (_machine) {
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
+ ptr_pcibios_find_device = prep_pcibios_find_device;
+ ptr_pcibios_find_class = prep_pcibios_find_class;
+ break;
+ case _MACH_Pmac:
+ ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
+ ptr_pcibios_find_device = pmac_pcibios_find_device;
+ ptr_pcibios_find_class = pmac_pcibios_find_class;
+ break;
+ case _MACH_chrp:
+ ptr_pcibios_read_config_byte = chrp_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = chrp_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = chrp_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = chrp_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = chrp_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = chrp_pcibios_write_config_dword;
+ ptr_pcibios_find_device = chrp_pcibios_find_device;
+ ptr_pcibios_find_class = chrp_pcibios_find_class;
+ break;
}
-}
-
-/*
- * Note: This routine has to access the PCI configuration space
- * for the PCI bridge chip (Intel 82378).
- */
-unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
-{
return mem_start;
}
-unsigned long route_pci_interrupts(void)
+__initfunc(unsigned long
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
{
- unsigned char *ibc_pirq = (unsigned char *)0x80800860;
- unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
- extern unsigned long isBeBox[];
- int i;
-
- if ( _machine == _MACH_Motorola)
- {
- switch (inb(0x800) & 0xF0)
- {
- case 0x10: /* MVME16xx */
- Motherboard_map_name = "Genesis";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map_name = "Series E";
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map_name = "Blackhawk (Powerstack)";
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
- }
- } else
- {
- if ( _machine == _MACH_IBM )
- {
- unsigned char pl_id;
- unsigned long flags;
- unsigned index;
- unsigned char fn, bus;
- unsigned int addr;
- unsigned char dma_mode, ide_mode;
- int i;
-
- Motherboard_map_name = "IBM 8xx (Carolina)";
- Motherboard_map = ibm8xx_pci_IRQ_map;
- Motherboard_routes = ibm8xx_pci_IRQ_routes;
-ll_printk("before loop\n");
-
- for (index = 0;
- !pcibios_find_device (PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CORAL,
- index, &bus, &fn); ++index)
- {
- pcibios_read_config_dword(bus, fn, 0x10, &addr);
- addr &= ~0x3;
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x",
- addr, dma_mode, ide_mode);*/
- /* Make CDROM non-DMA */
- ide_mode = (ide_mode & 0x0F) | 0x20;
- outb(0x25, addr);
- outb(ide_mode, addr+4);
- dma_mode = dma_mode & ~0x80;
- outb(0x26, addr);
- outb(dma_mode, addr+4);
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("=> DMA mode: %x, IDE mode: %x\n",
- dma_mode, ide_mode);*/
- }
-
- /* Setup the PCI INT mappings for the Carolina */
- /* These are PCI Interrupt Route Control [1|2] Register */
- outb(Carolina_PIRQ_routes[0], 0x0890);
- outb(Carolina_PIRQ_routes[1], 0x0891);
-
- pl_id=inb(0x0852);
- /*printk("CPU Planar ID is %#0x\n", pl_id);*/
-
- if (pl_id == 0x0C) {
- /* INDI */
- Motherboard_map[12] = 1;
- }
-ll_printk("before edge/level\n");
-#if 0
- /*printk("Changing IRQ mode\n");*/
- pl_id=inb(0x04d0);
- /*printk("Low mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-
- pl_id=inb(0x04d1);
- /*printk("Hi mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
- pl_id=inb(0x04d1);
- /*printk("Hi mask now %#0x\n", pl_id);*/
-#endif
- }
- }
-
- /* Set up mapping from slots */
- for (i = 1; i <= 4; i++)
- {
- ibc_pirq[i-1] = Motherboard_routes[i];
- }
- /* Enable PCI interrupts */
- *ibc_pcicon |= 0x20;
+ return mem_start;
}
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
new file mode 100644
index 000000000..a48385b3f
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -0,0 +1,423 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+ void *io_base;
+ int bus_number;
+ int max_bus;
+ struct bridge_data *next;
+ struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID 0x106b
+#define BANDIT_DEVID 1
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+ if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the revision id */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+ rev, bp->io_base);
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32((volatile unsigned int *)bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+ bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+ int bus;
+ struct bridge_data *bridge;
+
+ bridge_list = 0;
+ max_bus = 0;
+ add_bridges(find_devices("bandit"), &mem_start);
+ add_bridges(find_devices("chaos"), &mem_start);
+ bridges = (struct bridge_data **) mem_start;
+ mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+ memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+ for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+ for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+ bridges[bus] = bridge;
+
+ return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+ int *bus_range;
+ int len;
+ struct bridge_data *bp;
+
+ for (; dev != NULL; dev = dev->next) {
+ if (dev->n_addrs < 1) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+ bus_range[1]);
+ printk(" controlled by %s at %x\n",
+ dev->name, dev->addrs[0].address);
+ bp = (struct bridge_data *) *mem_ptr;
+ *mem_ptr += sizeof(struct bridge_data);
+ bp->cfg_addr = (volatile unsigned int *)
+ (dev->addrs[0].address + 0x800000);
+ bp->cfg_data = (volatile unsigned char *)
+ (dev->addrs[0].address + 0xc00000);
+ bp->io_base = (void *) dev->addrs[0].address;
+ ioremap(dev->addrs[0].address, 0x800000);
+ bp->bus_number = bus_range[0];
+ bp->max_bus = bus_range[1];
+ bp->next = bridge_list;
+ bp->node = dev;
+ bridge_list = bp;
+ if (bp->max_bus > max_bus)
+ max_bus = bp->max_bus;
+
+ if (strcmp(dev->name, "bandit") == 0)
+ init_bandit(bp);
+ }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr)
+{
+ unsigned int *reg;
+ int len;
+
+ reg = (unsigned int *) get_property(dev, "reg", &len);
+ if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+ /* doesn't look like a PCI device */
+ *bus_ptr = 0xff;
+ *devfn_ptr = 0xff;
+ return -1;
+ }
+ *bus_ptr = reg[0] >> 16;
+ *devfn_ptr = reg[0] >> 8;
+ return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_8(bp->cfg_data + (offset & 3));
+
+ if (offset == PCI_INTERRUPT_LINE) {
+ /*
+ * Open Firmware often doesn't initialize this
+ * register properly, so we find the node and see
+ * if it has an AAPL,interrupts property.
+ */
+ struct device_node *node;
+ unsigned int *reg;
+
+ for (node = bp->node->child; node != 0; node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ *val = node->intrs[0];
+ break;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffffffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ *val = in_le32((volatile unsigned int *)bp->cfg_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_8(bp->cfg_data + (offset & 3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x, vendev;
+ unsigned char h;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_VENDOR_ID, &x)
+ == PCIBIOS_SUCCESSFUL && x == vendev) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x;
+ unsigned char h;
+
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_CLASS_REVISION, &x)
+ == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
new file mode 100644
index 000000000..74a8ff92d
--- /dev/null
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -0,0 +1,271 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from "arch/alpha/kernel/setup.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include "time.h"
+
+/*
+ * A magic address and value to put into it on machines with the
+ * "ohare" I/O controller. This makes the IDE CD work on Starmaxes.
+ * Contributed by Harry Eaton.
+ */
+#define OMAGICPLACE ((volatile unsigned *) 0xf3000038)
+#define OMAGICCONT 0xbeff7a
+
+extern int root_mountflags;
+
+extern char command_line[];
+extern char saved_command_line[256];
+
+unsigned char drive_info;
+
+#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
+
+extern unsigned long find_available_memory(void);
+
+void pmac_setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ extern unsigned long *end_of_DRAM;
+ struct device_node *cpu;
+ int *fp;
+
+ strcpy(saved_command_line, command_line);
+ *cmdline_p = command_line;
+
+ *memory_start_p = find_available_memory();
+ *memory_end_p = (unsigned long) end_of_DRAM;
+
+ set_prom_callback();
+
+ *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
+
+ /* Set loops_per_sec to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0) {
+ switch (_get_PVR() >> 16) {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 20: /* 620 */
+ loops_per_sec = *fp;
+ break;
+ default: /* 601, 603, etc. */
+ loops_per_sec = *fp / 2;
+ }
+ } else
+ loops_per_sec = 50000000;
+ }
+}
+
+char *bootpath;
+char bootdevice[256];
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+unsigned long
+powermac_init(unsigned long mem_start, unsigned long mem_end)
+{
+ struct device_node *chosen_np, *ohare_np;
+
+ mem_start = pmac_find_bridges(mem_start, mem_end);
+ ohare_np = find_devices("ohare");
+ if (ohare_np != NULL) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(OMAGICPLACE, OMAGICCONT);
+ }
+ pmac_nvram_init();
+ via_cuda_init();
+ pmac_read_rtc_time();
+ pmac_find_display();
+ bootpath = NULL;
+ chosen_np = find_devices("chosen");
+ if (chosen_np != NULL)
+ bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
+ if (bootpath != NULL) {
+ /*
+ * There's a bug in the prom. (Why am I not surprised.)
+ * If you pass a path like scsi/sd@1:0 to canon, it returns
+ * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+ * That is, the scsi target number doesn't get preserved.
+ */
+ call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+ }
+ return mem_start;
+}
+
+void
+note_scsi_host(struct device_node *node, void *host)
+{
+ int l;
+ char *p;
+
+ l = strlen(node->full_name);
+ if (strncmp(node->full_name, bootdevice, l) == 0
+ && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+ boot_host = host;
+ p = strstr(bootpath, "/sd@");
+ if (p != NULL) {
+ p += 4;
+ boot_target = simple_strtoul(p, NULL, 10);
+ p = strchr(p, ':');
+ if (p != NULL)
+ boot_part = simple_strtoul(p + 1, NULL, 10);
+ }
+ }
+}
+
+void find_boot_device(void)
+{
+ int dev;
+
+ if (kdev_t_to_nr(ROOT_DEV) != 0)
+ return;
+ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+ if (boot_host == NULL)
+ return;
+#ifdef CONFIG_SCSI
+ dev = sd_find_target(boot_host, boot_target);
+ if (dev == 0)
+ return;
+ boot_dev = to_kdev_t(dev + boot_part);
+#endif
+ /* XXX should cope with booting from IDE also */
+}
+
+void note_bootable_part(kdev_t dev, int part)
+{
+ static int found_boot = 0;
+
+ if (!found_boot) {
+ find_boot_device();
+ found_boot = 1;
+ }
+ if (dev == boot_dev) {
+ ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+ boot_dev = NODEV;
+ printk(" (root)");
+ }
+}
+
+void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ struct device_node *np;
+ int i;
+ static struct device_node *atas;
+ static int atas_valid;
+
+ *p = 0;
+ *irq = 0;
+ if (!atas_valid) {
+ atas = find_devices("ATA");
+ atas_valid = 1;
+ }
+ for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
+ ;
+ if (np == NULL)
+ return;
+ if (np->n_addrs == 0) {
+ printk("ide: no addresses for device %s\n", np->full_name);
+ return;
+ }
+ if (np->n_intrs == 0) {
+ printk("ide: no intrs for device %s, using 13\n",
+ np->full_name);
+ *irq = 13;
+ } else {
+ *irq = np->intrs[0];
+ }
+ base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base + i * 0x10;
+ *p = base + 0x160;
+}
+
+int
+pmac_get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ char *model;
+ struct device_node *cpu;
+ int l, *fp;
+
+ l = 0;
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ l += sprintf(buffer, "%dMHz ", *fp / 1000000);
+ }
+
+ switch (pvr>>16) {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ case 9:
+ model = "604e";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+ return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
+ (pvr & 0xff00) >> 8, pvr & 0xff);
+}
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
new file mode 100644
index 000000000..3c1895088
--- /dev/null
+++ b/arch/ppc/kernel/pmac_support.c
@@ -0,0 +1,69 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+
+void pmac_nvram_init(void)
+{
+ struct device_node *dp;
+
+ dp = find_devices("nvram");
+ if (dp == NULL) {
+ printk(KERN_ERR "Can't find NVRAM device\n");
+ nvram_naddrs = 0;
+ return;
+ }
+ nvram_naddrs = dp->n_addrs;
+ if (nvram_naddrs == 1) {
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ } else if (nvram_naddrs == 2) {
+ nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ } else {
+ printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+ nvram_naddrs);
+ }
+}
+
+unsigned char nvram_read_byte(int addr)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ return nvram_data[(addr & 0x1fff) << 4];
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ return nvram_data[(addr & 0x1f) << 4];
+ }
+ return 0;
+}
+
+void nvram_write_byte(unsigned char val, int addr)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ nvram_data[(addr & 0x1fff) << 4] = val;
+ break;
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ nvram_data[(addr & 0x1f) << 4] = val;
+ break;
+ }
+ eieio();
+}
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
new file mode 100644
index 000000000..69a17321d
--- /dev/null
+++ b/arch/ppc/kernel/pmac_time.c
@@ -0,0 +1,87 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * At present, we use the decrementer register in the 601 CPU
+ * for our periodic interrupts. This will probably have to be
+ * changed for other processors.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "time.h"
+
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET 2082844800
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void pmac_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ int freq, *fp, divisor;
+
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ cpu = find_type_devices("cpu");
+ if (cpu == 0)
+ panic("can't find cpu node in time_init");
+ fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp == 0)
+ panic("can't get cpu timebase frequency");
+ freq = *fp * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n",
+ freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+unsigned long
+pmac_get_rtc_time(void)
+{
+ struct cuda_request req;
+
+ /* Get the time from the RTC */
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+ while (!req.got_reply)
+ cuda_poll();
+ if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+}
+
+int pmac_set_rtc_time(unsigned long nowtime)
+{
+ return 0;
+}
+
+/*
+ * We can't do this in time_init, because via_cuda_init hasn't
+ * been called at that stage.
+ */
+void
+pmac_read_rtc_time(void)
+{
+ xtime.tv_sec = pmac_get_rtc_time();
+ xtime.tv_usec = 0;
+}
diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl
index e31dea266..7036f4a62 100644
--- a/arch/ppc/kernel/ppc_asm.tmpl
+++ b/arch/ppc/kernel/ppc_asm.tmpl
@@ -187,7 +187,3 @@ n:
#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/* Missing instructions */
-#define bdne bc 0,2,
-
diff --git a/arch/ppc/kernel/ppc_defs.head b/arch/ppc/kernel/ppc_defs.head
new file mode 100644
index 000000000..fbe926459
--- /dev/null
+++ b/arch/ppc/kernel/ppc_defs.head
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
new file mode 100644
index 000000000..ea2a073eb
--- /dev/null
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -0,0 +1,221 @@
+/*
+ * $Id: ppc_htab.c,v 1.7 1997/08/24 19:33:32 cort Exp $
+ *
+ * PowerPC hash table management proc entry. Will show information
+ * about the current hash table and will allow changes to it.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes);
+static long ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count);
+static long long ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig);
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern unsigned long _SDR1;
+
+static struct file_operations ppc_htab_operations = {
+ ppc_htab_lseek, /* lseek */
+ ppc_htab_read, /* read */
+ ppc_htab_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc files can do almost nothing..
+ */
+struct inode_operations proc_ppc_htab_inode_operations = {
+ &ppc_htab_operations, /* default proc file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+
+/*
+ * print some useful info about the hash table. This function
+ * is _REALLY_ slow (see the nested for loops below) but nothing
+ * in here should be really timing critical. -- Cort
+ */
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes)
+{
+ int n = 0, valid;
+ unsigned int kptes = 0, overflow = 0, uptes = 0;
+ PTE *ptr;
+ struct task_struct *p;
+ char buffer[128];
+
+ if (nbytes < 0)
+ return -EINVAL;
+
+ /*
+ * compute user/kernel pte's table this info can be
+ * misleading since there can be valid (v bit set) entries
+ * in the table but their vsid is used by no process (mm->context)
+ * due to the way tlb invalidation is handled on the ppc
+ * -- Cort
+ */
+ for ( ptr = Hash ; ptr < Hash_end ; ptr += sizeof(PTE))
+ {
+ if (ptr->v)
+ {
+ /* make sure someone is using this context/vsid */
+ for_each_task(p)
+ {
+ if ( (ptr->vsid >> 4) == p->mm->context )
+ {
+ valid = 1;
+ break;
+ }
+ }
+ if ( !valid )
+ continue;
+ /* user not allowed read or write */
+ if (ptr->pp == PP_RWXX)
+ kptes++;
+ else
+ uptes++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+
+ n += sprintf( buffer,
+ "Size\t\t: %luKb\n"
+ "Buckets\t\t: %lu\n"
+ "Address\t\t: %08lx\n"
+ "Entries\t\t: %lu\n"
+ "User ptes\t: %u\n"
+ "Kernel ptes\t: %u\n"
+ "Overflows\t: %u\n"
+ "Percent full\t: %%%lu\n",
+ (unsigned long)(Hash_size>>10),
+ (Hash_size/(sizeof(PTE)*8)),
+ (unsigned long)Hash,
+ Hash_size/sizeof(PTE),
+ uptes,
+ kptes,
+ overflow,
+ ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+ );
+
+ if (file->f_pos >= strlen(buffer))
+ return 0;
+ if (n > strlen(buffer) - file->f_pos)
+ n = strlen(buffer) - file->f_pos;
+ copy_to_user(buf, buffer + file->f_pos, n);
+ file->f_pos += n;
+ return n;
+}
+
+/*
+ * Can't _yet_ adjust the hash table size while running. -- Cort
+ */
+static long
+ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count)
+{
+ unsigned long size;
+ extern void reset_SDR1(void);
+
+ if ( current->uid != 0 )
+ return -EACCES;
+
+ /* only know how to set size right now */
+ if ( strncmp( buffer, "size ", 5) )
+ return -EINVAL;
+
+ size = simple_strtoul( &buffer[5], NULL, 10 );
+
+ /* only allow to shrink */
+ if ( size >= Hash_size>>10 )
+ return -EINVAL;
+
+ /* minimum size of htab */
+ if ( size < 64 )
+ return -EINVAL;
+
+ /* make sure it's a multiple of 64k */
+ if ( size % 64 )
+ return -EINVAL;
+
+ printk("Hash table resize to %luk\n", size);
+ /*
+ * We need to rehash all kernel entries for the new htab size.
+ * Kernel only since we do a flush_tlb_all(). Since it's kernel
+ * we only need to bother with vsids 0-15. To avoid problems of
+ * clobbering un-rehashed values we put the htab at a new spot
+ * and put everything there.
+ * -- Cort
+ */
+ Hash_size = size<<10;
+ Hash_mask = (Hash_size >> 6) - 1;
+ _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+ flush_tlb_all();
+
+ reset_SDR1();
+ printk("done\n");
+ return count;
+}
+
+
+static long long
+ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return(file->f_pos);
+ case 1:
+ file->f_pos += offset;
+ return(file->f_pos);
+ case 2:
+ return(-EINVAL);
+ default:
+ return(-EINVAL);
+ }
+}
+
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
new file mode 100644
index 000000000..fd2ad89ff
--- /dev/null
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -0,0 +1,140 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bios32.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void do_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+extern unsigned lost_interrupts;
+extern void do_lost_interrupts(unsigned long);
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(lost_interrupts);
+EXPORT_SYMBOL(do_lost_interrupts);
+
+EXPORT_SYMBOL(atomic_add);
+EXPORT_SYMBOL(atomic_sub);
+EXPORT_SYMBOL(atomic_inc);
+EXPORT_SYMBOL(atomic_inc_return);
+EXPORT_SYMBOL(atomic_dec);
+EXPORT_SYMBOL(atomic_dec_return);
+EXPORT_SYMBOL(atomic_dec_and_test);
+
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(test_and_change_bit);
+#if 0
+EXPORT_SYMBOL(ffz);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strspn);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(memcmp);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(strlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(ioremap);
+
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__cli);
+EXPORT_SYMBOL(__sti);
+/*EXPORT_SYMBOL(__restore_flags);*/
+EXPORT_SYMBOL(_disable_interrupts);
+EXPORT_SYMBOL(_enable_interrupts);
+EXPORT_SYMBOL(flush_instruction_cache);
+EXPORT_SYMBOL(_get_PVR);
+EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(xchg_u32);
+
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(abort);
+EXPORT_SYMBOL(call_prom);
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(note_scsi_host);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
new file mode 100644
index 000000000..ffacd94c9
--- /dev/null
+++ b/arch/ppc/kernel/prep_pci.c
@@ -0,0 +1,436 @@
+/*
+ * $Id: prep_pci.c,v 1.7 1997/08/23 22:46:02 cort Exp $
+ * PReP pci functions.
+ * Originally by Gary Thomas
+ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * The motherboard routes/maps will disappear shortly. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
+#define MAX_DEVNR 22
+
+/* Which PCI interrupt line does a given device [slot] use? */
+/* Note: This really should be two dimensional based in slot/pin used */
+unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
+
+/* How is the 82378 PIRQ mapping setup? */
+unsigned char *Motherboard_routes;
+
+/* Tables for known hardware */
+
+/* Motorola PowerStack */
+static char Blackhawk_pci_IRQ_map[16] =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Blackhawk_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola MVME16xx */
+static char Genesis_pci_IRQ_map[16] =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Genesis_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola Series-E */
+static char Comet_pci_IRQ_map[16] =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Comet_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - FireCoral */
+ 4, /* Slot 12 - Ethernet PCIINTD# */
+ 2, /* Slot 13 - PCI Slot #2 */
+ 2, /* Slot 14 - S3 Video PCIINTD# */
+ 0, /* Slot 15 - onboard SCSI (INDI) [1] */
+ 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+ 0, /* Line 0 - unused */
+ 13, /* Line 1 */
+ 10, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+/* IBM Nobis and 850 */
+static char Nobis_pci_IRQ_map[23] ={
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+};
+
+static char Nobis_pci_IRQ_routes[] = {
+ 0, /* Line 0 - Unused */
+ 13, /* Line 1 */
+ 13, /* Line 2 */
+ 13, /* Line 3 */
+ 13 /* Line 4 */
+};
+
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
+#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+
+int
+prep_pcibios_read_config_dword (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned int *val)
+{
+ unsigned long _val;
+ unsigned long *ptr;
+ dev >>= 3;
+
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ _val = le32_to_cpu(*ptr);
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_read_config_word (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned short *val)
+{
+ unsigned short _val;
+ unsigned short *ptr;
+ dev >>= 3;
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *val = (unsigned short)0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ _val = le16_to_cpu(*ptr);
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_read_config_byte (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned char *val)
+{
+ unsigned char _val;
+ volatile unsigned char *ptr;
+ dev >>= 3;
+ /* Note: the configuration registers don't always have this right! */
+ if (offset == PCI_INTERRUPT_LINE)
+ {
+ *val = Motherboard_routes[Motherboard_map[dev]];
+/*printk("dev %d map %d route %d on board %d\n",
+ dev,Motherboard_map[dev],
+ Motherboard_routes[Motherboard_map[dev]],
+ *(unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1)));*/
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+ _val = *ptr;
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_dword (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned int val)
+{
+ unsigned long _val;
+ unsigned long *ptr;
+ dev >>= 3;
+ _val = le32_to_cpu(val);
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_word (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned short val)
+{
+ unsigned short _val;
+ unsigned short *ptr;
+ dev >>= 3;
+ _val = le16_to_cpu(val);
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_byte (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned char val)
+{
+ unsigned char _val;
+ unsigned char *ptr;
+ dev >>= 3;
+ _val = val;
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int prep_pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+/*printk("pcibios_find_device(): vendor %04x devid %04x index %d\n",
+ vendor,device_id,index);*/
+ for (dev = pci_devices; dev; dev = dev->next) {
+/*printk(" dev->vendor %04x dev->device %04x\n",
+ dev->vendor,dev->device);*/
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+int prep_pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+ unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+ unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+ int i;
+
+ if ( _machine == _MACH_Motorola)
+ {
+ switch (inb(0x800) & 0xF0)
+ {
+ case 0x10: /* MVME16xx */
+ Motherboard_map_name = "Genesis";
+ Motherboard_map = Genesis_pci_IRQ_map;
+ Motherboard_routes = Genesis_pci_IRQ_routes;
+ break;
+ case 0x20: /* Series E */
+ Motherboard_map_name = "Series E";
+ Motherboard_map = Comet_pci_IRQ_map;
+ Motherboard_routes = Comet_pci_IRQ_routes;
+ break;
+ case 0x40: /* PowerStack */
+ default: /* Can't hurt, can it? */
+ Motherboard_map_name = "Blackhawk (Powerstack)";
+ Motherboard_map = Blackhawk_pci_IRQ_map;
+ Motherboard_routes = Blackhawk_pci_IRQ_routes;
+ break;
+ }
+ } else if ( _machine == _MACH_IBM )
+ {
+ unsigned char pl_id;
+
+ if (inb(0x0852) == 0xFF) {
+ Motherboard_map_name = "IBM 850/860 Portable\n";
+ Motherboard_map = Nobis_pci_IRQ_map;
+ Motherboard_routes = Nobis_pci_IRQ_routes;
+ } else {
+ Motherboard_map_name = "IBM 8xx (Carolina)";
+ Motherboard_map = ibm8xx_pci_IRQ_map;
+ Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ }
+ /*printk("Changing IRQ mode\n");*/
+ pl_id=inb(0x04d0);
+ /*printk("Low mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask now %#0x\n", pl_id);*/
+ } else
+ {
+ printk("No known machine pci routing!\n");
+ return -1;
+ }
+
+ /* Set up mapping from slots */
+ for (i = 1; i <= 4; i++)
+ {
+ ibc_pirq[i-1] = Motherboard_routes[i];
+ }
+ /* Enable PCI interrupts */
+ *ibc_pcicon |= 0x20;
+ return 0;
+}
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
new file mode 100644
index 000000000..18e013964
--- /dev/null
+++ b/arch/ppc/kernel/prep_setup.c
@@ -0,0 +1,294 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+extern unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+
+extern char saved_command_line[256];
+
+void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
+}
+
+
+int
+prep_get_cpuinfo(char *buffer)
+{
+ extern char *Motherboard_map_name;
+ extern RESIDUAL res;
+ int i;
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+
+ switch (pvr>>16)
+ {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+
+#ifdef __SMP__
+#define CD(X) (cpu_data[n].X)
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+
+ len = sprintf(buffer,"processor\t: %d\n"
+ "cpu\t\t: %s\n"
+ "revision\t: %d.%d\n"
+ "upgrade\t\t: %s\n"
+ "clock\t\t: %dMHz\n"
+ "bus clock\t: %dMHz\n"
+ "machine\t\t: %s (sn %s)\n"
+ "pci map\t\t: %s\n",
+ CPUN,
+ model,
+ MAJOR(pvr), MINOR(pvr),
+ (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
+ (res.VitalProductData.ProcessorHz > 1024) ?
+ res.VitalProductData.ProcessorHz>>20 :
+ res.VitalProductData.ProcessorHz,
+ (res.VitalProductData.ProcessorBusHz > 1024) ?
+ res.VitalProductData.ProcessorBusHz>>20 :
+ res.VitalProductData.ProcessorBusHz,
+ res.VitalProductData.PrintableModel,
+ res.VitalProductData.Serial,
+ Motherboard_map_name
+ );
+
+ /* print info about SIMMs */
+ len += sprintf(buffer+len,"simms\t\t: ");
+ for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+ {
+ if ( res.Memories[i].SIMMSize != 0 )
+ len += sprintf(buffer+len,"%d:%dM ",i,
+ (res.Memories[i].SIMMSize > 1024) ?
+ res.Memories[i].SIMMSize>>20 :
+ res.Memories[i].SIMMSize);
+ }
+ len += sprintf(buffer+len,"\n");
+
+ /* TLB */
+ len += sprintf(buffer+len,"tlb\t\t:");
+ switch(res.VitalProductData.TLBAttrib)
+ {
+ case CombinedTLB:
+ len += sprintf(buffer+len," %d entries\n",
+ res.VitalProductData.TLBSize);
+ break;
+ case SplitTLB:
+ len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+ res.VitalProductData.I_TLBSize,
+ res.VitalProductData.D_TLBSize);
+ break;
+ case NoneTLB:
+ len += sprintf(buffer+len," not present\n");
+ break;
+ }
+
+ /* L1 */
+ len += sprintf(buffer+len,"l1\t\t: ");
+ switch(res.VitalProductData.CacheAttrib)
+ {
+ case CombinedCAC:
+ len += sprintf(buffer+len,"%dkB LineSize\n",
+ res.VitalProductData.CacheSize,
+ res.VitalProductData.CacheLineSize);
+ break;
+ case SplitCAC:
+ len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+ res.VitalProductData.I_CacheSize,
+ res.VitalProductData.D_CacheSize,
+ res.VitalProductData.D_CacheLineSize,
+ res.VitalProductData.D_CacheLineSize);
+ break;
+ case NoneCAC:
+ len += sprintf(buffer+len,"not present\n");
+ break;
+ }
+
+ /* L2 */
+ if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
+ {
+ len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
+ ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
+ (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
+ }
+ else
+ {
+ len += sprintf(buffer+len,"l2\t\t: not present\n");
+ }
+
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ CD(loops_per_sec+2500)/500000,
+ (CD(loops_per_sec+2500)/5000) % 100);
+
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+ "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
+ }
+ return len;
+}
+
+__initfunc(void
+prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
+{
+ extern char cmd_line[];
+ extern char _etext[], _edata[], _end[];
+ extern int panic_timeout;
+ unsigned char reg;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy( saved_command_line, cmd_line );
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = (unsigned long) Hash+Hash_size;
+ (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_sec = 50000000;
+
+ /* reboot on panic */
+ panic_timeout = 180;
+
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) _etext;
+ init_task.mm->end_data = (unsigned long) _edata;
+ init_task.mm->brk = (unsigned long) _end;
+
+ aux_device_present = 0xaa;
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ switch ( _machine )
+ {
+ case _MACH_IBM:
+ ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+ break;
+ case _MACH_Motorola:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+ break;
+ }
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+ /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+ if ( initrd_start )
+ {
+ if (initrd_end > *memory_end_p)
+ {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end,*memory_end_p);
+ initrd_start = 0;
+ }
+ }
+#endif
+
+ printk("Boot arguments: %s\n", cmd_line);
+
+ print_residual_device_info();
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
new file mode 100644
index 000000000..da0151ede
--- /dev/null
+++ b/arch/ppc/kernel/prep_time.c
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d). The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro. This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18 addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+ MOTO_RTC_MINUTES,0 /* alarm */,
+ MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */
+ MOTO_RTC_DAY_OF_WEEK,
+ MOTO_RTC_DAY_OF_MONTH,
+ MOTO_RTC_MONTH,
+ MOTO_RTC_YEAR, /* 9 */
+ MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+ if ( _machine == _MACH_IBM )
+ return CMOS_READ(addr);
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+ }
+
+ printk("Unknown machine in prep_cmos_clock_read()!\n");
+ return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+ if ( _machine == _MACH_IBM )
+ {
+ CMOS_WRITE(val,addr);
+ return;
+ }
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ outb(val,NVRAM_DATA);
+ return;
+ }
+ printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int prep_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ to_tm(nowtime, &tm);
+
+ save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+ prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ prep_cmos_clock_write(save_control, RTC_CONTROL);
+ prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ return 0;
+}
+
+unsigned long prep_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = prep_cmos_clock_read(RTC_SECONDS);
+ min = prep_cmos_clock_read(RTC_MINUTES);
+ hour = prep_cmos_clock_read(RTC_HOURS);
+ day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = prep_cmos_clock_read(RTC_MONTH);
+ year = prep_cmos_clock_read(RTC_YEAR);
+ } while (sec != prep_cmos_clock_read(RTC_SECONDS));
+ if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+#if 0
+void time_init(void)
+{
+ void (*irq_handler)(int, void *,struct pt_regs *);
+
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+
+ prep_calibrate_decr();
+
+ /* If we have the CPU hardware time counters, use them */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+{
+ prep_calibrate_decr_handler(irq,dev,regs);
+ do_timer(regs);
+
+ /* update the hw clock if:
+ * the time is marked out of sync (TIME_ERROR)
+ * or ~11 minutes have expired since the last update -- Cort
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if ( time_state == TIME_BAD ||
+ xtime.tv_sec > last_rtc_update + 660 )
+ /*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))*/
+ if (prep_set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+#ifdef CONFIG_HEARTBEAT
+ /* use hard disk LED as a heartbeat instead -- much more useful
+ for debugging -- Cort */
+ switch(kstat.interrupts[0] % 101)
+ {
+ /* act like an actual heart beat -- ie thump-thump-pause... */
+ case 0:
+ case 20:
+ outb(1,IBM_HDD_LED);
+ break;
+ case 7:
+ case 27:
+ outb(0,IBM_HDD_LED);
+ break;
+ case 100:
+ break;
+ }
+#endif
+}
+#endif
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index f24872063..5e194fedb 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -7,7 +7,7 @@
* Derived from "arch/i386/kernel/process.c"
* Copyright (C) 1995 Linus Torvalds
*
- * Modified by Cort Dougan (cort@cs.nmt.edu) and
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
* Paul Mackerras (paulus@cs.anu.edu.au)
*
* This program is free software; you can redistribute it and/or
@@ -28,22 +28,22 @@
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
#include <linux/config.h>
+#include <linux/elf.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/smp_lock.h>
+#include <asm/processor.h>
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
extern unsigned long _get_SP(void);
+
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
#undef IDLE_ZERO 1
@@ -59,7 +59,7 @@ task_top(struct task_struct *tsk)
{
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-
+
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;
@@ -69,9 +69,12 @@ struct mm_struct init_mm = INIT_MM;
union task_union init_task_union = { INIT_TASK };
int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
- return (1);
+ if (last_task_used_math == current)
+ giveup_fpu();
+ memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
+ return 1;
}
/* check to make sure the kernel stack is healthy */
@@ -80,7 +83,6 @@ int check_stack(struct task_struct *tsk)
unsigned long stack_top = kernel_stack_top(tsk);
unsigned long tsk_top = task_top(tsk);
int ret = 0;
- unsigned long *i;
#if 0
/* check tss magic */
@@ -98,7 +100,7 @@ int check_stack(struct task_struct *tsk)
if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
{
printk("stack out of bounds: %s/%d\n"
- " tsk_top %08x ksp %08x stack_top %08x\n",
+ " tsk_top %08lx ksp %08lx stack_top %08lx\n",
tsk->comm,tsk->pid,
tsk_top, tsk->tss.ksp, stack_top);
ret |= 2;
@@ -108,7 +110,7 @@ int check_stack(struct task_struct *tsk)
if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
{
printk("current stack ptr out of bounds: %s/%d\n"
- " tsk_top %08x sp %08x stack_top %08x\n",
+ " tsk_top %08lx sp %08lx stack_top %08lx\n",
current->comm,current->pid,
tsk_top, _get_SP(), stack_top);
ret |= 4;
@@ -143,15 +145,12 @@ switch_to(struct task_struct *prev, struct task_struct *new)
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
- /* turn off fpu for task last to run */
- /*prev->tss.regs->msr &= ~MSR_FP;*/
-
+
#ifdef SHOW_TASK_SWITCHES
printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
prev->comm,prev->pid,prev->tss.regs->nip,
@@ -160,289 +159,29 @@ switch_to(struct task_struct *prev, struct task_struct *new)
new_tss = &new->tss;
old_tss = &current->tss;
_switch(old_tss, new_tss, new->mm->context);
- /* turn off fpu for task last to run */
_enable_interrupts(s);
}
-
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
- struct task_struct *p;
- printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
- printk("last %x\n", last_task_used_math);
- printk("cur %x regs %x/%x tss %x/%x\n",
- current, current->tss.regs,regs,&current->tss,current->tss);
- for_each_task(p)
- {
- if ((long)p < KERNELBASE)
- {
- printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
- print_mm_info();
- __cli();
- while(1);
- }
- }
- return regs->gpr[3];
-#endif
-#if 0
- /* set the time in the cmos clock */
- unsigned long hwtime, nowtime;
- struct rtc_time tm;
-
- hwtime = get_cmos_time();
- to_tm(hwtime, &tm);
- printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
- tm.tm_mday, tm.tm_year);
- return;
-#endif
-}
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
-unsigned long zerocount = 0; /* # currently pre-zero'd pages */
-unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0; /* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
{
- unsigned long page;
- unsigned long s;
-
- if ( zero_list )
- {
- /* atomically remove this page from the list */
- asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
- " lwz %0,0(%1)\n" /* get next -- new zero_list */
- " stwcx. %0,0,%2\n" /* update zero_list */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list), "=&r" (page)
- : "r" (&zero_list)
- : "cc" );
- /* we can update zerocount after the fact since it is not
- * used for anything but control of a loop which doesn't
- * matter since it won't effect anything if it zero's one
- * less page -- Cort
- */
- atomic_inc((atomic_t *)&zeropage_hits);
- atomic_dec((atomic_t *)&zerocount);
- /* zero out the pointer to next in the page */
- *(unsigned long *)page = 0;
- return page;
- }
return 0;
}
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
- extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
- unsigned long tmp;
- pte_t ptep;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- sprintf(current->comm, "zero_paged");
- printk("Started zero_paged\n");
- /* want priority over idle task and powerd */
- current->priority = -98;
- current->counter = -98;
- __sti();
-
- while ( zerocount < 128 )
- {
- /*
- * Mark a page as reserved so we can mess with it
- * If we're interrupted we keep this page and our place in it
- * since we validly hold it and it's reserved for us.
- */
- pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
- if ( !pageptr )
- {
- printk("!pageptr in zero_paged\n");
- goto retry;
- }
-
- if ( need_resched )
- schedule();
-
- /*
- * Make the page no cache so we don't blow our cache with 0's
- */
- dir = pgd_offset( init_task.mm, pageptr );
- if (dir)
- {
- pmd = pmd_offset(dir, pageptr & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, pageptr & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- pte_uncache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
- }
- }
- }
-
- /*
- * Important here to not take time away from real processes.
- */
- for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
- {
- if ( need_resched )
- schedule();
- *(unsigned long *)(bytecount + pageptr) = 0;
- }
-
- /*
- * If we finished zero-ing out a page add this page to
- * the zero_list atomically -- we can't use
- * down/up since we can't sleep in idle.
- * Disabling interrupts is also a bad idea since we would
- * steal time away from real processes.
- * We can also have several zero_paged's running
- * on different processors so we can't interfere with them.
- * So we update the list atomically without locking it.
- * -- Cort
- */
- /* turn cache on for this page */
- pte_cache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-
- /* atomically add this page to the list */
- asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
- " stw %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
- " sync\n" /* let store settle */
-#endif
- " mr %0,%2\n" /* update zero_list in reg */
- " stwcx. %2,0,%1\n" /* update zero_list in mem */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list)
- : "r" (&zero_list), "r" (pageptr)
- : "cc" );
- /*
- * This variable is used in the above loop and nowhere
- * else so the worst that could happen is we would
- * zero out one more or one less page than we want
- * per processor on the machine. This is because
- * we could add our page to the list but not have
- * zerocount updated yet when another processor
- * reads it. -- Cort
- */
- atomic_inc((atomic_t *)&zerocount);
- atomic_inc((atomic_t *)&zerototal);
-retry:
- schedule();
- }
-}
-
-void powerd(void)
-{
- unsigned long msr, hid0;
-
- sprintf(current->comm, "powerd");
- __sti();
- while (1)
- {
- /* want priority over idle task 'swapper' -- Cort */
- current->priority = -99;
- current->counter = -99;
- asm volatile(
- /* clear powersaving modes and set nap mode */
- "mfspr %3,1008 \n\t"
- "andc %3,%3,%4 \n\t"
- "or %3,%3,%5 \n\t"
- "mtspr 1008,%3 \n\t"
- /* enter the mode */
- "mfmsr %0 \n\t"
- "oris %0,%0,%2 \n\t"
- "sync \n\t"
- "mtmsr %0 \n\t"
- "isync \n\t"
- : "=&r" (msr)
- : "0" (msr), "i" (MSR_POW>>16),
- "r" (hid0),
- "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
- "r" (HID0_NAP));
- if ( need_resched )
- schedule();
- /*
- * The ibm carolina spec says that the eagle memory
- * controller will detect the need for a snoop
- * and wake up the processor so we don't need to
- * check for cache operations that need to be
- * snooped. The ppc book says the run signal
- * must be asserted while napping for this though.
- * -- Cort
- */
- }
-}
-
-asmlinkage int sys_idle(void)
-{
- int ret = -EPERM;
- if (current->pid != 0)
- goto out;
-
-#ifdef IDLE_ZERO
- /*
- * want one per cpu since it would be nice to have all
- * processors who aren't doing anything
- * zero-ing pages since this daemon is lock-free
- * -- Cort
- */
- kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
- /* no powersaving modes on 601 - one per processor */
- if( (_get_PVR()>>16) != 1 )
- kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-
- /* endless loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
- for (;;)
- {
- schedule();
- }
- ret = 0;
-out:
- return ret;
-}
-
void show_regs(struct pt_regs * regs)
{
int i;
- printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+ printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
regs->nip, regs->xer, regs->link, regs,regs->trap);
- printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
- printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+ printk("TASK = %p[%d] '%s' mm->pgd %p ",
current, current->pid, current->comm, current->mm->pgd);
- printk("Last syscall: %d ", current->tss.last_syscall);
- printk("\nlast math %08X\n", last_task_used_math);
+ printk("Last syscall: %ld ", current->tss.last_syscall);
+ printk("\nlast math %p\n", last_task_used_math);
for (i = 0; i < 32; i++)
{
long r;
@@ -451,9 +190,9 @@ void show_regs(struct pt_regs * regs)
printk("GPR%02d: ", i);
}
- if ( get_user(r, &(regs->gpr[i])) )
+ if ( __get_user(r, &(regs->gpr[i])) )
goto out;
- printk("%08X ", r);
+ printk("%08lX ", r);
if ((i % 8) == 7)
{
printk("\n");
@@ -480,14 +219,14 @@ release_thread(struct task_struct *t)
}
/*
- * Copy a thread..
- */
+ * Copy a thread..
+ */
int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
- int i;
struct pt_regs * childregs;
+
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -497,13 +236,13 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
- p->tss.regs = (struct pt_regs *)(childregs);
- if (usp >= (unsigned long)regs)
- { /* Stack is in kernel space - must adjust */
- childregs->gpr[1] = (long)(childregs+1);
- } else
- { /* Provided stack is in user space */
+ p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+ p->tss.regs = childregs;
+ if (usp >= (unsigned long) regs) {
+ /* Stack is in kernel space - must adjust */
+ childregs->gpr[1] = (unsigned long)(childregs + 1);
+ } else {
+ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
@@ -511,24 +250,75 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
/*
* copy fpu info - assume lazy fpu switch now always
- * this should really be conditional on whether or
- * not the process has used the fpu
* -- Cort
*/
if ( last_task_used_math == current )
giveup_fpu();
-
+
memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
-
+
return 0;
}
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+ int argc;
+ char *p;
+ unsigned long e;
+ unsigned long aux_start, offset;
+
+ if (__get_user(argc, (int *)sp))
+ return;
+ sp += sizeof(int) + (argc + 1) * sizeof(char *);
+ /* skip over the environment pointers */
+ do {
+ if (__get_user(p, (char **)sp))
+ return;
+ sp += sizeof(char *);
+ } while (p != NULL);
+ aux_start = sp;
+ /* skip to the end of the auxiliary table */
+ do {
+ if (__get_user(e, (unsigned long *)sp))
+ return;
+ sp += 2 * sizeof(unsigned long);
+ } while (e != AT_NULL);
+ offset = ((aux_start + 15) & ~15) - aux_start;
+ if (offset != 0) {
+ do {
+ sp -= sizeof(unsigned long);
+ if (__get_user(e, (unsigned long *)sp)
+ || __put_user(e, (unsigned long *)(sp + offset)))
+ return;
+ } while (sp > aux_start);
+ }
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+ set_fs(USER_DS);
+ regs->nip = nip;
+ regs->gpr[1] = sp;
+ regs->msr = MSR_USER;
+ shove_aux_table(sp);
+}
+
+
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
int ret;
+
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
unlock_kernel();
@@ -541,26 +331,26 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
{
int error;
char * filename;
- filename = (int) getname((char *) a0);
+
+ filename = getname((char *) a0);
error = PTR_ERR(filename);
- if(IS_ERR(filename))
+ if (IS_ERR(filename))
goto out;
if ( last_task_used_math == current )
last_task_used_math = NULL;
error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
putname(filename);
-
out:
unlock_kernel();
return error;
}
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
{
unsigned long clone_flags = p1;
int res;
-
+
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
unlock_kernel();
@@ -571,34 +361,23 @@ void
print_backtrace(unsigned long *sp)
{
int cnt = 0;
- int i;
+ unsigned long i;
+
printk("Call backtrace: ");
- while ( !get_user(i, sp) && i)
- {
- if ( get_user( i, &sp[1] ) )
- return;
- printk("%08X ", i);
- if ( get_user( (ulong)sp, sp) )
- return;
- if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
- if (++cnt == 8)
- {
+ while (sp) {
+ if (__get_user( i, &sp[1] ))
+ break;
+ if (cnt++ % 7 == 0)
printk("\n");
- }
+ printk("%08lX ", i);
if (cnt > 32) break;
+ if (__get_user(sp, (unsigned long **)sp))
+ break;
}
printk("\n");
}
-inline void start_thread(struct pt_regs * regs,
- unsigned long eip, unsigned long esp)
-{
- set_fs(USER_DS);
- regs->nip = eip;
- regs->gpr[1] = esp;
- regs->msr = MSR_USER;
-}
-
+#if 0
/*
* Low level print for debugging - Cort
*/
@@ -651,3 +430,4 @@ void ll_puts(const char *s)
orig_x = x;
orig_y = y;
}
+#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
new file mode 100644
index 000000000..c7a566a14
--- /dev/null
+++ b/arch/ppc/kernel/prom.c
@@ -0,0 +1,524 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+#define getpromprop(node, name, buf, len) \
+ ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
+
+ihandle prom_stdout;
+ihandle prom_chosen;
+
+char command_line[256];
+int screen_initialized = 0;
+
+char prom_display_path[128];
+
+struct prom_args {
+ const char *service;
+ int nargs;
+ int nret;
+ void *args[10];
+} prom_args;
+
+struct pci_address {
+ unsigned a_hi;
+ unsigned a_mid;
+ unsigned a_lo;
+};
+
+struct pci_reg_property {
+ struct pci_address addr;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+struct pci_range {
+ struct pci_address addr;
+ unsigned phys;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+void (*prom_entry)(void *);
+extern int prom_trashed;
+
+static int prom_callback(struct prom_args *);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+ unsigned long, unsigned long);
+static void check_display(void);
+static int prom_next_node(phandle *);
+
+extern int pmac_display_supported(const char *);
+extern void enter_prom(void *);
+
+void
+prom_exit()
+{
+ struct prom_args args;
+
+ args.service = "exit";
+ args.nargs = 0;
+ args.nret = 0;
+ enter_prom(&args);
+ for (;;) /* should never get here */
+ ;
+}
+
+void *
+call_prom(const char *service, int nargs, int nret, ...)
+{
+ va_list list;
+ int i;
+
+ if (prom_trashed)
+ panic("prom called after its memory was reclaimed");
+ prom_args.service = service;
+ prom_args.nargs = nargs;
+ prom_args.nret = nret;
+ va_start(list, nret);
+ for (i = 0; i < nargs; ++i)
+ prom_args.args[i] = va_arg(list, void *);
+ va_end(list);
+ for (i = 0; i < nret; ++i)
+ prom_args.args[i + nargs] = 0;
+ enter_prom(&prom_args);
+ return prom_args.args[nargs];
+}
+
+void
+prom_print(const char *msg)
+{
+ const char *p, *q;
+ const char *crlf = "\r\n";
+
+ if (screen_initialized)
+ return;
+ for (p = msg; *p != 0; p = q) {
+ for (q = p; *q != 0 && *q != '\n'; ++q)
+ ;
+ if (q > p)
+ call_prom("write", 3, 1, prom_stdout, p, q - p);
+ if (*q != 0) {
+ ++q;
+ call_prom("write", 3, 1, prom_stdout, crlf, 2);
+ }
+ }
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+void
+prom_init(char *params, int unused, void (*pp)(void *))
+{
+ /* First get a handle for the stdout device */
+ if ( ! have_of() )
+ return;
+ prom_entry = pp;
+ prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
+ if (prom_chosen == (void *)-1)
+ prom_exit();
+ call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
+ (void *) sizeof(prom_stdout));
+
+ /*
+ * If we were booted via quik, params points to the physical address
+ * of the command-line parameters.
+ * If we were booted from an xcoff image (i.e. netbooted or
+ * booted from floppy), we get the command line from the bootargs
+ * property of the /chosen node. If an initial ramdisk is present,
+ * params and unused are used for initrd_start and initrd_size,
+ * otherwise they contain 0xdeadbeef.
+ */
+ command_line[0] = 0;
+ if ((unsigned long) params >= 0x4000
+ && (unsigned long) params < 0x800000
+ && unused == 0) {
+ strncpy(command_line, params+KERNELBASE, sizeof(command_line));
+ } else {
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ((unsigned long) params - KERNELBASE < 0x800000
+ && unused != 0 && unused != 0xdeadbeef) {
+ initrd_start = (unsigned long) params;
+ initrd_end = initrd_start + unused;
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ }
+#endif
+ call_prom("getprop", 4, 1, prom_chosen, "bootargs",
+ command_line, sizeof(command_line));
+ }
+ command_line[sizeof(command_line) - 1] = 0;
+
+ check_display();
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later. However, OF may fall over if we do that after
+ * we've taken over the MMU and done set_prom_callback.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void
+check_display()
+{
+ phandle node;
+ ihandle ih;
+ char type[16], name[64], path[128];
+
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ name[0] = 0;
+ getpromprop(node, "name", name, sizeof(name));
+ if (pmac_display_supported(name))
+ /* we have a supported display */
+ return;
+ }
+ printk(KERN_INFO "No supported display found\n");
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ /* It seems OF doesn't null-terminate the path :-( */
+ memset(path, 0, sizeof(path));
+ if ((int) call_prom("package-to-path", 3, 1,
+ node, path, sizeof(path) - 1) < 0) {
+ printk(KERN_WARNING "can't get path for display %p\n",
+ node);
+ continue;
+ }
+ ih = call_prom("open", 1, 1, path);
+ if (ih == 0 || ih == (ihandle) -1) {
+ printk(KERN_WARNING "couldn't open display %s\n",
+ path);
+ continue;
+ }
+ printk(KERN_INFO "Opened display device %s using "
+ "Open Firmware\n", path);
+ strcpy(prom_display_path, path);
+ break;
+ }
+}
+
+static int
+prom_next_node(phandle *nodep)
+{
+ phandle node;
+
+ if ((node = *nodep) != 0
+ && (*nodep = call_prom("child", 1, 1, node)) != 0)
+ return 1;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ for (;;) {
+ if ((node = call_prom("parent", 1, 1, node)) == 0)
+ return 0;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ }
+}
+
+/*
+ * Callback routine for the PROM to call us.
+ * No services are implemented yet :-)
+ */
+static int
+prom_callback(struct prom_args *argv)
+{
+ printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
+ argv->nargs, argv->nret);
+ return -1;
+}
+
+/*
+ * Register a callback with the Open Firmware PROM so it can ask
+ * us to map/unmap memory, etc.
+ */
+void
+set_prom_callback()
+{
+ call_prom("set-callback", 1, 1, prom_callback);
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ prom_exit();
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+
+static struct device_node *allnodes;
+static struct device_node **allnextp;
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+unsigned long
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+ phandle root;
+
+ root = call_prom("peer", 1, 1, (phandle)0);
+ if (root == (phandle)0)
+ panic("couldn't get device tree root\n");
+ allnextp = &allnodes;
+ mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+ *allnextp = 0;
+ return mem_start;
+}
+
+static unsigned long
+inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
+ unsigned long mem_start, unsigned long mem_end)
+{
+ struct reg_property *reg, *rp;
+ struct pci_reg_property *pci_addrs;
+ int l, i;
+ phandle child;
+ struct device_node *np;
+ struct property *pp, **prev_propp;
+ char *prev_name;
+
+ np = (struct device_node *) mem_start;
+ mem_start += sizeof(struct device_node);
+ memset(np, 0, sizeof(*np));
+ np->node = node;
+ *allnextp = np;
+ allnextp = &np->allnext;
+ np->parent = dad;
+ if (dad != 0) {
+ /* we temporarily use the `next' field as `last_child'. */
+ if (dad->next == 0)
+ dad->child = np;
+ else
+ dad->next->sibling = np;
+ dad->next = np;
+ }
+
+ /* get and store all properties */
+ prev_propp = &np->properties;
+ prev_name = 0;
+ for (;;) {
+ pp = (struct property *) mem_start;
+ pp->name = (char *) (pp + 1);
+ if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+ pp->name) <= 0)
+ break;
+ mem_start = ALIGN((unsigned long)pp->name
+ + strlen(pp->name) + 1);
+ pp->value = (unsigned char *) mem_start;
+ pp->length = (int)
+ call_prom("getprop", 4, 1, node, pp->name, pp->value,
+ mem_end - mem_start);
+ if (pp->length < 0)
+ panic("hey, where did property %s go?", pp->name);
+ mem_start = ALIGN(mem_start + pp->length);
+ prev_name = pp->name;
+ *prev_propp = pp;
+ prev_propp = &pp->next;
+ }
+ *prev_propp = 0;
+
+ np->name = get_property(np, "name", 0);
+ np->type = get_property(np, "device_type", 0);
+
+ /* get all the device addresses and interrupts */
+ reg = (struct reg_property *) mem_start;
+ pci_addrs = (struct pci_reg_property *)
+ get_property(np, "assigned-addresses", &l);
+ i = 0;
+ if (pci_addrs != 0) {
+ while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+ /* XXX assumes PCI addresses mapped 1-1 to physical */
+ reg[i].address = pci_addrs[i].addr.a_lo;
+ reg[i].size = pci_addrs[i].size_lo;
+ ++i;
+ }
+ } else {
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0) {
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ reg[i].address = rp[i].address + base_address;
+ reg[i].size = rp[i].size;
+ ++i;
+ }
+ }
+ }
+ if (i > 0) {
+ np->addrs = reg;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct reg_property);
+ }
+
+ np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (np->intrs != 0)
+ np->n_intrs = l / sizeof(int);
+
+ /* get the node's full name */
+ l = (int) call_prom("package-to-path", 3, 1, node,
+ (char *) mem_start, mem_end - mem_start);
+ if (l >= 0) {
+ np->full_name = (char *) mem_start;
+ np->full_name[l] = 0;
+ mem_start = ALIGN(mem_start + l + 1);
+ }
+
+ if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+ base_address = np->addrs[0].address;
+
+ child = call_prom("child", 1, 1, node);
+ while (child != (void *)0) {
+ mem_start = inspect_node(child, np, base_address,
+ mem_start, mem_end);
+ child = call_prom("peer", 1, 1, child);
+ }
+
+ return mem_start;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+ return np;
+ return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+ struct property *pp;
+
+ for (pp = np->properties; pp != 0; pp = pp->next)
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ return pp->value;
+ }
+ return 0;
+}
+
+void
+print_properties(struct device_node *np)
+{
+ struct property *pp;
+ char *cp;
+ int i, n;
+
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ printk(KERN_INFO "%s", pp->name);
+ for (i = strlen(pp->name); i < 16; ++i)
+ printk(" ");
+ cp = (char *) pp->value;
+ for (i = pp->length; i > 0; --i, ++cp)
+ if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+ || (i == 1 && *cp != 0))
+ break;
+ if (i == 0 && pp->length > 1) {
+ /* looks like a string */
+ printk(" %s\n", (char *) pp->value);
+ } else {
+ /* dump it in hex */
+ n = pp->length;
+ if (n > 64)
+ n = 64;
+ if (pp->length % 4 == 0) {
+ unsigned int *p = (unsigned int *) pp->value;
+
+ n /= 4;
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 4) == 0)
+ printk("\n ");
+ printk(" %08x", *p++);
+ }
+ } else {
+ unsigned char *bp = pp->value;
+
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 16) == 0)
+ printk("\n ");
+ printk(" %02x", *bp++);
+ }
+ }
+ printk("\n");
+ if (pp->length > 64)
+ printk(" ... (length = %d)\n",
+ pp->length);
+ }
+ }
+}
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index a5ec62d20..8a5839d1f 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -171,8 +171,11 @@ repeat:
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) < max_mapnr)
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ if (MAP_NR(page) < max_mapnr) {
+ unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+ *(unsigned long *) phys_addr = data;
+ flush_icache_range(phys_addr, phys_addr+4);
+ }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -364,7 +367,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKUSR: {
unsigned long tmp;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
ret = -EIO;
goto out;
}
@@ -378,13 +381,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (addr < PT_FPR0) {
tmp = get_reg(child, addr);
}
-#if 1
- else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
if (last_task_used_math == child)
giveup_fpu();
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
-#endif
else
ret = -EIO;
if (!ret)
@@ -400,7 +401,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
goto out;
addr = addr >> 2; /* temporary hack. */
@@ -508,7 +509,7 @@ asmlinkage void syscall_trace(void)
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c
new file mode 100644
index 000000000..4084f9f62
--- /dev/null
+++ b/arch/ppc/kernel/residual.c
@@ -0,0 +1,144 @@
+/*
+ * $Id: residual.c,v 1.2 1997/08/25 06:54:56 cort Exp $
+ *
+ * Code to deal with the PReP residual data.
+ *
+ * Written by: Cort Dougan (cort@cs.nmt.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/pnp.h>
+
+
+/*
+ * Spit out some info about residual data
+ */
+void print_residual_device_info(void)
+{
+ int i;
+ union _PnP_TAG_PACKET *pkt;
+ PPC_DEVICE *dev;
+#define did dev->DeviceId
+
+ /* make sure we have residual data first */
+ if ( res.ResidualLength == 0 )
+ return;
+
+ printk("Residual: %ld devices\n", res.ActualNumDevices);
+ for ( i = 0;
+ i < res.ActualNumDevices ;
+ i++)
+ {
+ dev = &res.Devices[i];
+ /*
+ * pci devices
+ */
+ if ( did.BusId & PCIDEVICE )
+ {
+ printk("PCI Device:");
+ /* unknown vendor */
+ if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
+ printk(" id %08lx types %d/%d", did.DevId,
+ did.BaseType, did.SubType);
+ /* known vendor */
+ else
+ printk(" %s %s",
+ pci_strvendor(did.DevId>>16),
+ pci_strdev(did.DevId>>16,
+ did.DevId&0xffff)
+ );
+
+ if ( did.BusId & PNPISADEVICE )
+ {
+ printk(" pnp:");
+ /* get pnp info on the device */
+ pkt = (union _PnP_TAG_PACKET *)
+ &res.DevicePnPHeap[dev->AllocatedOffset];
+ for (; pkt->S1_Pack.Tag != DF_END_TAG;
+ pkt++ )
+ {
+ if ( (pkt->S1_Pack.Tag == S4_Packet) ||
+ (pkt->S1_Pack.Tag == S4_Packet_flags) )
+ printk(" irq %02x%02x",
+ pkt->S4_Pack.IRQMask[0],
+ pkt->S4_Pack.IRQMask[1]);
+ }
+ }
+ printk("\n");
+ continue;
+ }
+ /*
+ * isa devices
+ */
+ if ( did.BusId & ISADEVICE )
+ {
+ printk("ISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * eisa devices
+ */
+ if ( did.BusId & EISADEVICE )
+ {
+ printk("EISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * proc bus devices
+ */
+ if ( did.BusId & PROCESSORDEVICE )
+ {
+ printk("ProcBus Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * pcmcia devices
+ */
+ if ( did.BusId & PCMCIADEVICE )
+ {
+ printk("PCMCIA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ printk("Unknown bus access device: busid %lx\n",
+ did.BusId);
+ }
+}
+
+
+
+
+
+
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index e69de29bb..f3769cad0 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -0,0 +1,268 @@
+/*
+ * $Id: setup.c,v 1.16 1997/08/27 22:06:54 cort Exp $
+ * Common prep/pmac boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/openpic.h>
+
+#include <asm/cuda.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+/* copy of the residual data */
+RESIDUAL res;
+int _machine;
+
+/*
+ * Perhaps we can put the pmac screen_info[] here
+ * on pmac as well so we don't need the ifdef's.
+ * Until we get multiple-console support in here
+ * that is. -- Cort
+ */
+#if defined(CONFIG_CHRP) || defined(CONFIG_PREP )
+struct screen_info screen_info = {
+ 0, 25, /* orig-x, orig-y */
+ { 0, 0 }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 25, /* orig-video-lines */
+ 1, /* orig-video-isVGA */
+ 16 /* orig-video-points */
+};
+
+/*
+ * I really need to add multiple-console support... -- Cort
+ */
+int pmac_display_supported(char *name)
+{
+ return 0;
+}
+int sd_find_target(void *a, int b)
+{
+ return 0;
+}
+void pmac_find_display(void)
+{
+}
+
+#endif
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init() )
+ */
+unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ extern unsigned long initrd_start, initrd_end;
+ extern char cmd_line[256];
+#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
+ _machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+ /* make a copy of residual data */
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
+ if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+ _machine = _MACH_IBM;
+ else
+ _machine = _MACH_Motorola;
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_CHRP
+ _machine = _MACH_chrp;
+#endif /* CONFIG_CHRP */
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ io_base = 0;
+ pci_dram_offset = 0;
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ io_base = 0x80000000;
+ pci_dram_offset = 0x80000000;
+#ifdef CONFIG_BLK_DEV_RAM
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_RAM */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ break;
+ case _MACH_chrp:
+ /* LongTrail */
+ io_base = 0xf8000000;
+ pci_dram_offset = 0;
+ /* take care of initrd if we have one */
+ if ( r4 ) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+ /* take care of cmd line */
+ if ( r6 ) {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ break;
+ default:
+ printk("Unknown machine type in identify_machine!\n");
+ }
+ return 0;
+}
+
+/* cmd is ignored for now... */
+void machine_restart(char *cmd)
+{
+ struct cuda_request req;
+ unsigned long flags;
+ unsigned long i = 10000;
+
+ switch(_machine)
+ {
+ case _MACH_Pmac:
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ _disable_interrupts();
+
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( i != 0 ) i++;
+ panic("restart failed\n");
+ break;
+
+ case _MACH_chrp:
+ openpic_init_processor(1<<0);
+ break;
+ }
+}
+
+void machine_power_off(void)
+{
+ struct cuda_request req;
+
+ if ( _machine == _MACH_Pmac )
+ {
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ }
+ else /* prep or chrp */
+ {
+ machine_restart(NULL);
+ }
+}
+
+void machine_halt(void)
+{
+ if ( _machine == _MACH_Pmac )
+ {
+#if 0
+ prom_exit(); /* doesn't work because prom is trashed */
+#else
+ machine_power_off(); /* for now */
+#endif
+ }
+ else /* prep or chrp */
+ machine_restart(NULL);
+
+}
+
+void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ if ( _machine == _MACH_Pmac )
+ pmac_ide_init_hwif_ports(p,base,irq);
+ else /* prep */
+ prep_ide_init_hwif_ports(p,base,irq);
+
+}
+
+/*
+ * Will merge more into here later -- Cort
+ */
+int get_cpuinfo(char *buffer)
+{
+ extern int pmac_get_cpuinfo(char *);
+ extern int chrp_get_cpuinfo(char *);
+ extern int prep_get_cpuinfo(char *);
+
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ return pmac_get_cpuinfo(buffer);
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ return prep_get_cpuinfo(buffer);
+ break;
+ case _MACH_chrp:
+ return chrp_get_cpuinfo(buffer);
+ break;
+ }
+ printk("Unknown machine %d in get_cpuinfo()\n",_machine);
+ return 0;
+}
+
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+ return memory_start;
+}
+
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+ extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void chrp_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ case _MACH_chrp:
+ return chrp_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ }
+ printk("Unknown machine %d in setup_arch()\n",_machine);
+}
+
+
+
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 2f602059c..3151d266a 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/elf.h>
#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
@@ -36,6 +37,10 @@
#define PAUSE_AFTER_SIGNAL
#undef PAUSE_AFTER_SIGNAL
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
@@ -71,32 +76,52 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg
}
}
+/*
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack. SE and BE
+ * should not be in this list since gdb may want to change these. I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+
/*
* This sets regs->esp even though we don't actually use sigstacks yet..
*/
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
- struct sigcontext_struct *sc;
- struct pt_regs *int_regs;
- int signo, ret;
+ struct sigcontext_struct *sc, sigctx;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
-#if 1
- if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >= KERNELBASE))
+ sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
-#endif
- sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
- get_user(current->blocked, &sc->oldmask);
- current->blocked &= _BLOCKABLE;
- get_user(int_regs, &sc->regs);
- get_user(signo, &sc->signal);
+ current->blocked = sigctx.oldmask & _BLOCKABLE;
sc++; /* Pop signal 'context' */
#ifdef DEBUG_SIGNALS
-printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+ printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
+ sigctx.signal);
#endif
- if (sc == (struct sigcontext_struct *)(int_regs)) {
- /* Last stacked signal */
- memcpy(regs, int_regs, sizeof(*regs));
+ if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers */
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+
+ if (copy_from_user(current->tss.fpr,
+ (unsigned long *)sigctx.regs + ELF_NGREG,
+ ELF_NFPREG * sizeof(double)))
+ goto badframe;
+
if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
@@ -106,15 +131,17 @@ printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
regs->result = 0;
}
ret = regs->result;
+
} else {
/* More signals to go */
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- get_user(regs->gpr[3], &sc->signal);
- get_user(int_regs, (struct pt_regs **) &sc->regs);
- regs->gpr[4] = (unsigned long) int_regs;
- regs->link = (unsigned long) (int_regs+1);
- get_user(regs->nip, &sc->handler);
- ret = regs->gpr[3];
+ regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+ goto badframe;
+ regs->gpr[3] = ret = sigctx.signal;
+ regs->gpr[4] = (unsigned long) sigctx.regs;
+ regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
+ + ELF_NFPREG * sizeof(double);
+ regs->nip = sigctx.handler;
}
return ret;
@@ -142,6 +169,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
unsigned long *frame = NULL;
unsigned long *trampoline;
unsigned long *regs_ptr;
+ double *fpregs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
@@ -164,7 +192,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -204,7 +232,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
@@ -257,18 +285,33 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
- /* Build trampoline code on stack */
- frame -= 2;
+ /*
+ * Build trampoline code on stack, and save gp and fp regs.
+ * The 56 word hole is because programs using the rs6000/xcoff
+ * style calling sequence can save up to 19 gp regs and 18 fp regs
+ * on the stack before decrementing sp.
+ */
+ frame -= 2 + 56;
trampoline = frame;
- /* verify stack is valid for writing regs struct */
- if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || ((unsigned long) frame >= KERNELBASE ))
- goto badframe;
- put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
- put_user(0x44000002UL, trampoline+1); /* sc */
- frame -= sizeof(*regs) / sizeof(long);
+ frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
+ fpregs_ptr = (double *) frame;
+ frame -= ELF_NGREG;
regs_ptr = frame;
- copy_to_user(regs_ptr, regs, sizeof(*regs));
+ /* verify stack is valid for writing to */
+ if (verify_area(VERIFY_WRITE, frame,
+ (ELF_NGREG + 2) * sizeof(long)
+ + ELF_NFPREG * sizeof(double)))
+ goto badframe;
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (__copy_to_user(regs_ptr, regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
+ || __copy_to_user(fpregs_ptr, current->tss.fpr,
+ ELF_NFPREG * sizeof(double))
+ || __put_user(0x38007777UL, trampoline) /* li r0,0x7777 */
+ || __put_user(0x44000002UL, trampoline+1)) /* sc */
+ goto badframe;
+
signr = 1;
sa = current->sig->action;
@@ -279,24 +322,29 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
- if (verify_area(VERIFY_WRITE,(void *)frame,
- sizeof(struct sigcontext_struct)/sizeof(long)))
+ if (verify_area(VERIFY_WRITE, frame,
+ sizeof(struct sigcontext_struct)))
goto badframe;
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- put_user(nip, &sc->handler);
- put_user(oldmask, &sc->oldmask); /* was current->blocked */
- put_user(regs_ptr, &sc->regs);
- put_user(signr, &sc->signal);
+ if (__put_user(nip, &sc->handler)
+ || __put_user(oldmask, &sc->oldmask)
+ || __put_user(regs_ptr, &sc->regs)
+ || __put_user(signr, &sc->signal))
+ goto badframe;
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
- regs->gpr[4] = (unsigned long)regs_ptr;
+ regs->gpr[4] = (unsigned long) regs_ptr;
}
+
+ frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
+ if (put_user(regs->gpr[1], frame))
+ goto badframe;
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ regs->gpr[1] = (unsigned long) frame;
/* The DATA cache must be flushed here to insure coherency */
/* between the DATA & INSTRUCTION caches. Since we just */
@@ -305,8 +353,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
/* cache for new data, we have to force the data to go on to */
/* memory and flush the instruction cache to force it to look */
/* there. The following function performs this magic */
- store_cache_range((unsigned long) trampoline,
- (unsigned long) (trampoline + 2));
+ flush_icache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
return 1;
badframe:
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index bfdccdee6..b7bac7a6a 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -1,15 +1,25 @@
/*
* linux/arch/ppc/kernel/sys_ppc.c
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
* Adapted from the i386 version by Gary Thomas
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
*
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/PPC
* platform.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -20,11 +30,11 @@
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/sys.h>
#include <linux/ipc.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
-
void
check_bugs(void)
{
@@ -32,32 +42,32 @@ check_bugs(void)
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
{
- printk("sys_ioperm()\n");
+ printk(KERN_ERR "sys_ioperm()\n");
return -EIO;
}
int sys_iopl(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_vm86(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_modify_ldt(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
/*
@@ -65,7 +75,8 @@ int sys_modify_ldt(int a1, int a2, int a3, int a4)
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
{
int version, ret;
@@ -73,138 +84,113 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
version = call >> 16; /* hack for backward compatibility */
call &= 0xffff;
- if (call <= SEMCTL)
- switch (call) {
- case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
- case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
- case SEMCTL: {
- union semun fourth;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (get_user(fourth.__pad, (void **) ptr))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
- }
- default:
- ret = -EINVAL;
- goto out;
+ ret = -EINVAL;
+ switch (call) {
+ case SEMOP:
+ ret = sys_semop (first, (struct sembuf *)ptr, second);
+ break;
+ case SEMGET:
+ ret = sys_semget (first, second, third);
+ break;
+ case SEMCTL: {
+ union semun fourth;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+ || (ret = get_user(fourth.__pad, (void **)ptr)))
+ break;
+ ret = sys_semctl (first, second, third, fourth);
+ break;
}
- if (call <= MSGCTL)
- switch (call) {
- case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
- second, third);
- goto out;
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
- }
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ case MSGSND:
+ ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+ break;
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+ || (ret = copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp))))
+ break;
+ ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+ third);
+ break;
}
- case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
- case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
default:
- ret = -EINVAL;
- goto out;
+ ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+ second, fifth, third);
+ break;
}
- if (call <= SHMCTL)
- switch (call) {
- case SHMAT:
- switch (version) {
- case 0: default: {
- ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
- if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ break;
+ case MSGGET:
+ ret = sys_msgget ((key_t) first, second);
+ break;
+ case MSGCTL:
+ ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ break;
+ case SHMAT:
+ switch (version) {
+ default: {
+ ulong raddr;
+
+ if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+ sizeof(ulong))))
+ break;
+ ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ break;
+ ret = put_user (raddr, (ulong *) third);
+ break;
}
- case 1: /* iBCS2 emulator entry point */
- ret = -EINVAL;
- if (get_fs() != get_ds())
- goto out;
- ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
- goto out;
- }
- case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
- case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
- case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
- default:
- ret = -EINVAL;
- goto out;
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ break;
+ ret = sys_shmat (first, (char *) ptr, second,
+ (ulong *) third);
+ break;
}
- else
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
-}
-
+ break;
+ case SHMDT:
+ ret = sys_shmdt ((char *)ptr);
+ break;
+ case SHMGET:
+ ret = sys_shmget (first, second, third);
+ break;
+ case SHMCTL:
+ ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ break;
+ }
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
- lock_kernel();
- panic("scsi_register_module");
- unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
- lock_kernel();
- panic("scsi_unregister_module");
unlock_kernel();
+ return ret;
}
-#endif
/*
* sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way unix traditionally does this, though.
*/
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(int *fildes)
{
int fd[2];
int error;
- error = verify_area(VERIFY_WRITE,fildes,8);
+ error = verify_area(VERIFY_WRITE, fildes, 8);
if (error)
return error;
+ lock_kernel();
error = do_pipe(fd);
+ unlock_kernel();
if (error)
return error;
- put_user(fd[0],0+fildes);
- put_user(fd[1],1+fildes);
+ if (__put_user(fd[0],0+fildes)
+ || __put_user(fd[1],1+fildes))
+ return -EFAULT; /* should we close the fds? */
return 0;
}
@@ -213,13 +199,18 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
unsigned long fd, off_t offset)
{
struct file * file = NULL;
+ int ret = -EBADF;
+
+ lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- return do_mmap(file, addr, len, prot, flags, offset);
+ ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+ unlock_kernel();
+ return ret;
}
extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -233,15 +224,15 @@ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timev
asmlinkage int
ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int err;
if ( (unsigned long)n >= 4096 )
{
unsigned long *buffer = (unsigned long *)n;
- if ( get_user(n, buffer) ||
- get_user(inp,buffer+1) ||
- get_user(outp,buffer+2) ||
- get_user(exp,buffer+3) ||
- get_user(tvp,buffer+4) )
+ if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+ || __get_user(n, buffer)
+ || __get_user(inp, ((fd_set **)(buffer+1)))
+ || __get_user(outp, ((fd_set **)(buffer+2)))
+ || __get_user(exp, ((fd_set **)(buffer+3)))
+ || __get_user(tvp, ((struct timeval **)(buffer+4))))
return -EFAULT;
}
return sys_select(n, inp, outp, exp, tvp);
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index e69de29bb..fc172d7a7 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -0,0 +1,268 @@
+/*
+ * $Id: time.c,v 1.10 1997/08/27 22:06:56 cort Exp $
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
+int (*set_rtc_time)(unsigned long);
+
+/* keep track of when we need to update the rtc */
+unsigned long last_rtc_update = 0;
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601 (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601 1
+#define COUNT_PERIOD_DEN_601 1000
+
+unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
+unsigned count_period_num; /* 1 decrementer count equals */
+unsigned count_period_den; /* count_period_num / count_period_den us */
+
+/* Accessor functions for the decrementer register. */
+inline unsigned long
+get_dec(void)
+{
+ int ret;
+
+ asm volatile("mfspr %0,22" : "=r" (ret) :);
+ return ret;
+}
+
+inline void
+set_dec(int val)
+{
+ asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+ int dval, d;
+ while ((dval = get_dec()) < 0) {
+ /*
+ * Wait for the decrementer to change, then jump
+ * in and add decrementer_count to its value
+ * (quickly, before it changes again!)
+ */
+ while ((d = get_dec()) == dval)
+ ;
+ set_dec(d + decrementer_count);
+ do_timer(regs);
+ /*
+ * update the rtc when needed
+ */
+ if ( xtime.tv_sec > last_rtc_update + 660 )
+ if (set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += (decrementer_count - get_dec())
+ * count_period_num / count_period_den;
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ int frac_tick;
+
+ last_rtc_update = 0; /* so the rtc gets updated soon */
+
+ frac_tick = tv->tv_usec % (1000000 / HZ);
+ save_flags(flags);
+ cli();
+ xtime.tv_sec = tv->tv_sec;
+ xtime.tv_usec = tv->tv_usec - frac_tick;
+ set_dec(frac_tick * count_period_den / count_period_num);
+ restore_flags(flags);
+}
+
+
+void
+time_init(void)
+{
+ /* pmac hasn't yet called via_cuda_init() */
+ if ( _machine != _MACH_Pmac )
+ {
+
+ if ( _machine == _MACH_chrp )
+ xtime.tv_sec = chrp_get_rtc_time();
+ else /* assume prep */
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+ /*
+ * mark the rtc/on-chip timer as in sync
+ * so we don't update right away
+ */
+ last_rtc_update = xtime.tv_sec;
+ }
+
+ if ((_get_PVR() >> 16) == 1) {
+ /* 601 processor: dec counts down by 128 every 128ns */
+ decrementer_count = DECREMENTER_COUNT_601;
+ count_period_num = COUNT_PERIOD_NUM_601;
+ count_period_den = COUNT_PERIOD_DEN_601;
+ }
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ pmac_calibrate_decr();
+ set_rtc_time = pmac_set_rtc_time;
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ prep_calibrate_decr();
+ set_rtc_time = prep_set_rtc_time;
+ break;
+ case _MACH_chrp:
+ chrp_calibrate_decr();
+ set_rtc_time = chrp_set_rtc_time;
+ break;
+ }
+ set_dec(decrementer_count);
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems. On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+void prep_calibrate_decr(void)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+ __sti();
+ while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+ restore_flags(flags);
+ free_irq( 0, NULL);
+}
+
+void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
+{
+ int freq, divisor;
+ static unsigned long t1 = 0, t2 = 0;
+
+ if ( !t1 )
+ t1 = get_dec();
+ else if (!t2)
+ {
+ t2 = get_dec();
+ t2 = t1-t2; /* decr's in 1/HZ */
+ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ *done_ptr = 1;
+ }
+}
+
+void chrp_calibrate_decr(void)
+{
+ int freq, fp, divisor;
+
+ fp = 16666000; /* hardcoded for now */
+ freq = fp*60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
new file mode 100644
index 000000000..9ce5921dc
--- /dev/null
+++ b/arch/ppc/kernel/time.h
@@ -0,0 +1,74 @@
+/*
+ * $Id: time.h,v 1.5 1997/08/27 22:06:58 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/mc146818rtc.h>
+
+/* time.c */
+__inline__ unsigned long get_dec(void);
+__inline__ void set_dec(int val);
+void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
+void prep_calibrate_decr(void);
+void pmac_calibrate_decr(void);
+void chrp_calibrate_decr(void);
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+ unsigned int, unsigned int, unsigned int);
+
+/* pmac/prep/chrp_time.c */
+unsigned long prep_get_rtc_time(void);
+unsigned long pmac_get_rtc_time(void);
+unsigned long chrp_get_rtc_time(void);
+int prep_set_rtc_time(unsigned long nowtime);
+int pmac_set_rtc_time(unsigned long nowtime);
+int chrp_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+
+#define TICK_SIZE tick
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+extern void inline to_tm(int tim, struct rtc_time * tm)
+{
+ register int i;
+ register long hms, day;
+
+ day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
+ day -= days_in_year(i);
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; day >= days_in_month(i); i++)
+ day -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i;
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+}
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 84ce1c5ca..edfcb4d63 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -1,9 +1,15 @@
/*
* linux/arch/ppc/kernel/traps.c
*
- * Copyright (C) 1995 Gary Thomas
- * Adapted for PowerPC by Gary Thomas
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
*/
/*
@@ -24,9 +30,21 @@
#include <linux/config.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
/*
* Trap & Exception support
@@ -43,40 +61,53 @@ _exception(int signr, struct pt_regs *regs)
if (!user_mode(regs))
{
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
}
+void
MachineCheckException(struct pt_regs *regs)
{
if ( !user_mode(regs) )
{
+#ifdef CONFIG_XMON
+ if (xmon_fault_handler) {
+ xmon_fault_handler(regs);
+ return;
+ }
+#endif
printk("Machine check in kernel mode.\n");
printk("Caused by (from msr): ");
- printk("regs %08x ",regs);
+ printk("regs %p ",regs);
switch( regs->msr & 0x0000F000)
{
case (1<<12) :
printk("Machine check signal - probably due to mm fault\n"
"with mmu off\n");
- break;
+ break;
case (1<<13) :
printk("Transfer error ack signal\n");
- break;
+ break;
case (1<<14) :
printk("Data parity signal\n");
- break;
+ break;
case (1<<15) :
printk("Address parity signal\n");
- break;
+ break;
default:
printk("Unknown values in msr\n");
}
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("");
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("machine check");
}
_exception(SIGSEGV, regs);
}
@@ -105,33 +136,71 @@ RunModeException(struct pt_regs *regs)
_exception(SIGTRAP, regs);
}
+void
ProgramCheckException(struct pt_regs *regs)
{
- if (current->flags & PF_PTRACED)
+ if (regs->msr & 0x100000) {
+ /* IEEE FP exception */
+ _exception(SIGFPE, regs);
+ } else if (regs->msr & 0x20000) {
+ /* trap exception */
+#ifdef CONFIG_XMON
+ if (xmon_bpt(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
- else
+ } else {
_exception(SIGILL, regs);
+ }
}
+void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+ if (xmon_sstep(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
}
+void
AlignmentException(struct pt_regs *regs)
{
+ int fixed;
+
+ if (last_task_used_math == current)
+ giveup_fpu();
+ fixed = fix_alignment(regs);
+ if (fixed == 1) {
+ regs->nip += 4; /* skip over emulated instruction */
+ return;
+ }
+ if (fixed == -EFAULT) {
+ /* fixed == -EFAULT means the operand address was bad */
+ bad_page_fault(regs, regs->dar);
+ return;
+ }
_exception(SIGBUS, regs);
}
+void
+PromException(struct pt_regs *regs, int trap)
+{
+ regs->trap = trap;
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+ regs->trap, regs->nip, regs->msr);
+ /* probably should turn up the toes here */
+}
+
+void
trace_syscall(struct pt_regs *regs)
{
- static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
current, current->pid, regs->nip, regs->link, regs->gpr[0],
regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
- if (++count == 20)
- {
- count = 0;
- }
}
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 68b33f047..8b84ce2ae 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -1,38 +1,11 @@
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
-
-HOST_CC = gcc
-
-L_TARGET = lib.o
-L_OBJS = checksum.o cksum_support.o string.o
-
-${L_TARGET}: $(L_OBJS)
- $(LD) -r -o ${L_TARGET} $(L_OBJS)
-
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
+#
+# Makefile for ppc-specific library files..
+#
-modules:
+.S.o:
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-dummy:
+O_TARGET = lib.o
+O_OBJS = checksum.o string.o strcase.o
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S
new file mode 100644
index 000000000..6c53d50ff
--- /dev/null
+++ b/arch/ppc/lib/checksum.S
@@ -0,0 +1,192 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+_TEXT()
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+ lwz r0,0(r3)
+ lwzu r5,4(r3)
+ addi r4,r4,-2
+ addc r0,r0,r5
+ mtctr r4
+1: lwzu r4,4(r3)
+ adde r0,r0,r4
+ bdnz 1b
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ * csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */
+_GLOBAL(csum_tcpudp_magic)
+ rlwimi r5,r6,16,0,15 /* put proto in upper half of len */
+ addc r0,r3,r4 /* add 4 32-bit words together */
+ adde r0,r0,r5
+ adde r0,r0,r7
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+ addic r0,r5,0
+ subi r3,r3,4
+ srwi. r6,r4,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r5,r3,2 /* Align buffer to longword boundary */
+ beq+ 1f
+ lhz r5,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r4,r4,2
+ addc r0,r0,r5
+ srwi. r6,r4,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */
+ adde r0,r0,r5 /* be unnecessary to unroll this loop */
+ bdnz 2b
+ andi. r4,r4,3
+3: cmpi 0,r4,2
+ blt+ 4f
+ lhz r5,4(r3)
+ addi r3,r3,2
+ subi r4,r4,2
+ adde r0,r0,r5
+4: cmpi 0,r4,1
+ bne+ 5f
+ lbz r5,4(r3)
+ slwi r5,r5,8 /* Upper byte of word */
+ adde r0,r0,r5
+5: addze r3,r0 /* add in final carry */
+ blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+ addic r0,r6,0
+ subi r3,r3,4
+ subi r4,r4,4
+ srwi. r6,r5,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r9,r4,2 /* Align dst to longword boundary */
+ beq+ 1f
+81: lhz r6,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r5,r5,2
+91: sth r6,4(r4)
+ addi r4,r4,2
+ addc r0,r0,r6
+ srwi. r6,r5,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */
+92: stwu r6,4(r4) /* be unnecessary to unroll this loop */
+ adde r0,r0,r6
+ bdnz 82b
+ andi. r5,r5,3
+3: cmpi 0,r5,2
+ blt+ 4f
+83: lhz r6,4(r3)
+ addi r3,r3,2
+ subi r5,r5,2
+93: sth r6,4(r4)
+ addi r4,r4,2
+ adde r0,r0,r6
+4: cmpi 0,r5,1
+ bne+ 5f
+84: lbz r6,4(r3)
+94: stb r6,4(r4)
+ slwi r6,r6,8 /* Upper byte of word */
+ adde r0,r0,r6
+5: addze r3,r0 /* add in final carry */
+ blr
+
+.section .fixup,"ax"
+
+src_error_1:
+ li r6,0
+ subi r5,r5,2
+95: sth r6,4(r4)
+ addi r4,r4,2
+ srwi. r6,r5,2
+ beq 3f
+ mtctr r6
+src_error_2:
+ li r6,0
+96: stwu r6,4(r4)
+ bdnz 96b
+3: andi. r5,r5,3
+ beq src_error
+src_error_3:
+ li r6,0
+ mtctr r5
+ addi r4,r4,3
+97: stbu r6,1(r4)
+ bdnz 97b
+src_error:
+ cmpi 0,r7,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r7)
+1: addze r3,r0
+ blr
+
+dst_error:
+ cmpi 0,r8,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r8)
+1: addze r3,r0
+ blr
+
+.section __ex_table,"a"
+ .long 81b,src_error_1
+ .long 91b,dst_error
+ .long 82b,src_error_2
+ .long 92b,dst_error
+ .long 83b,src_error_3
+ .long 93b,dst_error
+ .long 84b,src_error_3
+ .long 94b,dst_error
+ .long 95b,dst_error
+ .long 96b,dst_error
+ .long 97b,dst_error
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
new file mode 100644
index 000000000..a9e40bce9
--- /dev/null
+++ b/arch/ppc/lib/strcase.c
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
new file mode 100644
index 000000000..96378dec1
--- /dev/null
+++ b/arch/ppc/lib/string.S
@@ -0,0 +1,345 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/errno.h>
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
+2: li r3,0
+ blr
+
+ .global memchr
+memchr:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r3,r3,-1
+1: lbzu r0,1(r3)
+ cmpw 0,r0,r4
+ bdnzf 2,1b
+ beqlr
+2: li r3,0
+ blr
+
+ .globl __copy_tofrom_user
+__copy_tofrom_user:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ li r3,0 /* success return value */
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+11: lwzu r8,8(r4)
+12: stw r7,4(r6)
+13: stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+14: lwzu r0,4(r4)
+ addi r5,r5,-4
+15: stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+16: stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+17: stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
+ .long 11b,99b
+ .long 12b,99b
+ .long 13b,99b
+ .long 14b,99b
+ .long 15b,99b
+ .long 4b,99b
+ .long 16b,99b
+ .long 6b,99b
+ .long 17b,99b
+.text
+
+ .globl __clear_user
+__clear_user:
+ addi r6,r3,-4
+ li r3,0
+ li r5,0
+ cmplwi 0,r4,4
+ blt 7f
+11: stwu r5,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r4,r0,r4
+ subf r6,r0,r6
+ rlwinm r0,r4,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r5,4(r6)
+ bdnz 1b
+6: andi. r4,r4,3
+7: cmpwi 0,r4,0
+ beqlr
+ mtctr r4
+ addi r6,r6,3
+8: stbu r5,1(r6)
+ bdnz 8b
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 11b,99b
+ .long 1b,99b
+ .long 8b,99b
+.text
+
+ .globl __strncpy_from_user
+__strncpy_from_user:
+ addi r6,r3,-1
+ addi r4,r4,-1
+ cmpwi 0,r5,0
+ beq 2f
+ mtctr r5
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ beq 3f
+2: addi r6,r6,1
+3: subf r3,r3,r6
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
+.text
+
+ .globl strlen_user
+strlen_user:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ addi r3,r3,1
+ blr
+99: li r3,0
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
diff --git a/arch/ppc/mkdiff b/arch/ppc/mkdiff
new file mode 100644
index 000000000..304eb9428
--- /dev/null
+++ b/arch/ppc/mkdiff
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch
+diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch
diff --git a/arch/ppc/mkdist b/arch/ppc/mkdist
new file mode 100644
index 000000000..80408b741
--- /dev/null
+++ b/arch/ppc/mkdist
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
+date=`date +'%y%m%d'`
+
+echo zImage-$V.$P.$S-$date
+echo System.map-$V.$P.$S-$date
+
+rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date
+rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date
+
diff --git a/arch/ppc/mktar b/arch/ppc/mktar
new file mode 100644
index 000000000..a50112ff6
--- /dev/null
+++ b/arch/ppc/mktar
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux
diff --git a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
index 13aeab6ca..2b07c7227 100644
--- a/arch/ppc/mm/Makefile
+++ b/arch/ppc/mm/Makefile
@@ -7,28 +7,7 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.s.o:
- $(AS) -o $*.o $<
-.c.s:
- $(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS = fault.o init.o extable.o
-OBJS = fault.o init.o extable.o
-
-mm.o: $(OBJS)
- $(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c
new file mode 100644
index 000000000..77e3171bc
--- /dev/null
+++ b/arch/ppc/mm/extable.c
@@ -0,0 +1,65 @@
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ const struct exception_table_entry *mid;
+ for ( mid = first; mid < last; mid++)
+ {
+ if ( mid->insn == value )
+ return mid->fixup;
+ }
+ return 0;
+#if 0
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+#endif
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+
+#if 1 /*ndef CONFIG_MODULES*/
+ /* There is only the kernel to search. */
+ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+ if (ret) return ret;
+#else
+ /* The kernel is the last "module" -- no need to treat it special. */
+ struct module *mp;
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->ex_table_start == NULL)
+ continue;
+ ret = search_one_table(mp->ex_table_start,
+ mp->ex_table_end - 1, addr);
+ if (ret) return ret;
+ }
+#endif
+
+ return 0;
+}
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index fea722780..67b94d809 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -1,8 +1,12 @@
/*
* arch/ppc/mm/fault.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
* Modified by Cort Dougan and Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
@@ -26,40 +30,42 @@
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
- make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
#endif
extern void die_if_kernel(char *, struct pt_regs *, long);
void bad_page_fault(struct pt_regs *, unsigned long);
void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
- struct task_struct *tsk = current;
- extern unsigned _end[];
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
- current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
if (xmon_fault_handler && regs->trap == 0x300) {
xmon_fault_handler();
return;
}
+ if (error_code & 0x00400000) {
+ /* DABR match */
+ if (xmon_dabr_match(regs))
+ return;
+ }
#endif
if (in_interrupt()) {
static int complained;
@@ -68,14 +74,18 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long er
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
+#endif
}
}
- if (current == NULL)
- goto bad_area;
-
-do_page:
+ if (current == NULL) {
+ bad_page_fault(regs, address);
+ return;
+ }
down(&mm->mmap_sem);
- vma = find_vma(tsk->mm, address);
+ vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
@@ -84,7 +94,7 @@ do_page:
goto bad_area;
if (expand_stack(vma, address))
goto bad_area;
-
+
good_area:
if (error_code & 0xb5700000)
/* an error such as lwarx to I/O controller space,
@@ -98,67 +108,45 @@ good_area:
/* a read */
} else {
/* protection fault */
- if ( error_code & 0x08000000 )
+ if (error_code & 0x08000000)
goto bad_area;
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
handle_mm_fault(current, vma, address, error_code & 0x02000000);
- up(&mm->mmap_sem);
- /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
- current->comm,current->pid,address,regs->msr);*/
- /* not needed since flush_page_to_ram() works */
-#if 0
- flush_page(address);
-#endif
+ up(&mm->mmap_sem);
return;
-
+
bad_area:
- up(&current->mm->mmap_sem);
+ up(&mm->mmap_sem);
bad_page_fault(regs, address);
}
-
void
bad_page_fault(struct pt_regs *regs, unsigned long address)
{
- extern unsigned int probingmem;
- struct task_struct *tsk = current;
unsigned long fixup;
-
+
+ if (user_mode(regs)) {
+ force_sig(SIGSEGV, current);
+ return;
+ }
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->nip)) != 0) {
- if ( user_mode(regs) )
- printk("Exception from user mode\n");
-#if 0
- printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif
regs->nip = fixup;
return;
}
- if ( user_mode(regs) )
- {
- force_sig(SIGSEGV, tsk);
- return;
- }
-
-bad_kernel_access:
- /* make sure it's not a bootup probe test */
- if ( probingmem )
- {
- probingmem = 0;
- return;
- }
/* kernel has accessed a bad area */
show_regs(regs);
- print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
- xmon(regs);
+ print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
#endif
- panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
- regs->nip,address,tsk->comm,tsk->pid);
+ panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
+ regs->nip,regs->link,address,current->comm,current->pid);
}
unsigned long va_to_phys(unsigned long address)
@@ -189,6 +177,10 @@ unsigned long va_to_phys(unsigned long address)
return (0);
}
+#if 0
+/*
+ * Misc debugging functions. Please leave them here. -- Cort
+ */
void print_pte(struct _PTE p)
{
printk(
@@ -210,7 +202,8 @@ unsigned long htab_phys_to_va(unsigned long address)
for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
{
if ( ptr->rpn == (address>>12) )
- printk("phys %08X -> va ???\n",
+ printk("phys %08lX -> va ???\n",
address);
}
}
+#endif
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index d46975996..8503401b4 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -31,54 +31,58 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/stddef.h>
-#ifdef CONFIG_PMAC
#include <asm/prom.h>
-#endif
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
-#ifdef CONFIG_PREP
#include <asm/residual.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h> /* for initrd_* */
#endif
+int prom_trashed;
int next_mmu_context;
+unsigned long _SDR1;
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int mem_init_done;
extern pgd_t swapper_pg_dir[];
extern char _start[], _end[];
extern char etext[], _stext[];
-/* References to section boundaries */
extern char __init_begin, __init_end;
+extern RESIDUAL res;
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-extern unsigned long *find_end_of_memory(void);
+/* Hardwired MMU segments */
+#if defined(CONFIG_PREP) || defined(CONFIG_PMAC)
+#define MMU_SEGMENT_1 0x80000000
+#define MMU_SEGMENT_2 0xc0000000
+#endif /* CONFIG_PREP || CONFIG_PMAC */
+#ifdef CONFIG_CHRP
+#define MMU_SEGMENT_1 0xf0000000 /* LongTrail */
+#define MMU_SEGMENT_2 0xc0000000
+#endif /* CONFIG_CHRP */
-#undef MAP_RAM_WITH_SEGREGS 1
-#ifdef CONFIG_PMAC
void *find_mem_piece(unsigned, unsigned);
static void mapin_ram(void);
static void inherit_prom_translations(void);
-#endif
-#ifdef CONFIG_PREP
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
-int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);
-#endif
-
static void hash_init(void);
static void *MMU_get_page(void);
-void map_page(struct thread_struct *, unsigned long va,
+void map_page(struct task_struct *, unsigned long va,
unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long *find_end_of_memory(void);
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int mem_init_done;
+/*
+ * this tells the prep system to map all of ram with the segregs
+ * instead of the bats. I'd like to get this to apply to the
+ * pmac as well then have everything use the bats -- Cort
+ */
+#undef MAP_RAM_WITH_SEGREGS 1
-#ifdef CONFIG_PREP
-#ifdef HASHSTATS
-extern unsigned long evicts;
-#endif /* HASHSTATS */
/*
* these are used to setup the initial page tables
* They can waste up to an entire page since the
@@ -88,8 +92,6 @@ extern unsigned long evicts;
unsigned int probingmem = 0;
unsigned int mmu_pages_count = 0;
char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
-unsigned long _TotalMemory;
-#endif /* CONFIG_PREP */
/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -120,7 +122,6 @@ pte_t __bad_page(void)
return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
}
-#ifdef CONFIG_PMAC
#define MAX_MEM_REGIONS 32
phandle memory_pkg;
@@ -128,7 +129,6 @@ struct mem_pieces {
int n_regions;
struct reg_property regions[MAX_MEM_REGIONS];
};
-
struct mem_pieces phys_mem;
struct mem_pieces phys_avail;
struct mem_pieces prom_mem;
@@ -138,7 +138,6 @@ static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
static void print_mem_pieces(struct mem_pieces *);
unsigned long avail_start;
-int prom_trashed;
/*
* Read in a property describing some pieces of memory.
@@ -272,10 +271,10 @@ find_mem_piece(unsigned size, unsigned align)
* Our text, data, bss use something over 1MB, starting at 0.
* Open Firmware may be using 1MB at the 4MB point.
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *pmac_find_end_of_memory(void)
{
unsigned long a, total;
- unsigned long h, kstart, ksize;
+ unsigned long kstart, ksize;
extern char _stext[], _end[];
int i;
@@ -325,20 +324,6 @@ unsigned long *find_end_of_memory(void)
remove_mem_piece(&phys_avail, kstart, ksize, 0);
remove_mem_piece(&prom_mem, kstart, ksize, 0);
- /*
- * Allow 64k of hash table for every 16MB of memory,
- * up to a maximum of 2MB.
- */
- for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
- ;
- Hash_size = h;
- Hash_mask = (h >> 6) - 1;
-
- /* Find some memory for the hash table. */
- Hash = find_mem_piece(Hash_size, Hash_size);
- printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- total >> 20, Hash_size >> 10, Hash);
-
return __va(total);
}
@@ -353,6 +338,9 @@ unsigned long find_available_memory(void)
int i;
unsigned long a, free;
unsigned long start, end;
+
+ if ( _machine != _MACH_Pmac )
+ return 0;
free = 0;
for (i = 0; i < phys_avail.n_regions - 1; ++i) {
@@ -366,7 +354,6 @@ unsigned long find_available_memory(void)
avail_start = (unsigned long) __va(a);
return avail_start;
}
-#endif /* CONFIG_PMAC */
void show_mem(void)
{
@@ -399,14 +386,21 @@ void show_mem(void)
"Ctx", "Ctx<<4", "Last Sys", "pc", "task");
for_each_task(p)
{
- printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+ printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
p->comm,p->pid,
p->mm->count,p->mm->context,
p->mm->context<<4, p->tss.last_syscall,
user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
- p);
+ (ulong)p);
if ( p == current )
- printk(" current");
+ printk("current");
+ if ( p == last_task_used_math )
+ {
+ if ( p == current )
+ printk(",");
+ printk("last math");
+ }
+
printk("\n");
}
}
@@ -434,76 +428,68 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
unsigned long addr;
-#ifdef CONFIG_PMAC
int i;
- unsigned long lim;
-#endif
+ unsigned long a, lim;
int codepages = 0;
int datapages = 0;
int initpages = 0;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
- num_physpages = max_mapnr = MAP_NR(high_memory);
-
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
+ max_mapnr = MAP_NR(high_memory);
+ num_physpages = max_mapnr; /* RAM is assumed contiguous */
+
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
-
-#ifdef CONFIG_PMAC
- remove_mem_piece(&phys_avail, __pa(avail_start),
- start_mem - avail_start, 1);
-
- for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
- set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-
- for (i = 0; i < phys_avail.n_regions; ++i) {
- a = (unsigned long) __va(phys_avail.regions[i].address);
- lim = a + phys_avail.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+
+ if ( _machine == _MACH_Pmac )
+ {
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
- }
- phys_avail.n_regions = 0;
-
- /* free the prom's memory */
- for (i = 0; i < prom_mem.n_regions; ++i) {
- a = (unsigned long) __va(prom_mem.regions[i].address);
- lim = a + prom_mem.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+ phys_avail.n_regions = 0;
+
+ /* free the prom's memory */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
+ prom_trashed = 1;
}
- prom_trashed = 1;
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_PREP
- /* mark mem used by kernel as reserved, mark other unreserved */
- for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ else /* prep */
{
- /* skip hash table gap */
- if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
- continue;
- if ( addr < (ulong) /*Hash_end*/ start_mem )
- set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
- else
- clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ /* mark mem used by kernel as reserved, mark other unreserved */
+ for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ {
+ /* skip hash table gap */
+ if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+ continue;
+ if ( addr < (ulong) /*Hash_end*/ start_mem )
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ else
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
}
for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if(PageReserved(mem_map + MAP_NR(addr))) {
+ if (PageReserved(mem_map + MAP_NR(addr))) {
if (addr < (ulong) etext)
codepages++;
- /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
- initpages++;*/
+ else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ initpages++;
else if (addr < (ulong) start_mem)
datapages++;
continue;
@@ -515,9 +501,8 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
#endif /* CONFIG_BLK_DEV_INITRD */
free_page(addr);
}
-
-#endif /* CONFIG_PREP */
- printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+
+ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
@@ -534,7 +519,6 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
*/
void free_initmem(void)
{
- unsigned long addr;
unsigned long a;
unsigned long num_freed_pages = 0;
@@ -548,16 +532,14 @@ void free_initmem(void)
num_freed_pages++;
}
-#if 0
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- num_freed_pages++;
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- mem_map[MAP_NR(addr)].count = 1;
- free_page(addr);
+ a = (unsigned long)(&__init_begin);
+ for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
+ mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(a)].count, 1);
+ free_page(a);
}
-#endif
- printk ("Freeing unused kernel memory: %dk freed\n",
+
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(num_freed_pages * PAGE_SIZE) >> 10);
}
@@ -576,29 +558,23 @@ void si_meminfo(struct sysinfo *val)
val->totalram++;
if (!atomic_read(&mem_map[i].count))
continue;
- val->sharedram += atomic_read(&mem_map[i].count)-1;
+ val->sharedram += atomic_read(&mem_map[i].count) - 1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
return;
}
-/* Kernel MMU setup & lowest level hardware support */
-
-unsigned long _SDR1; /* Hardware SDR1 image */
-
-#ifdef CONFIG_PREP
-
BAT BAT0 =
{
{
- 0x80000000>>17, /* bepi */
+ MMU_SEGMENT_1>>17, /* bepi */
BL_256M, /* bl */
1, /* vs -- supervisor mode valid */
1, /* vp -- user mode valid */
},
{
- 0x80000000>>17, /* brpn */
+ MMU_SEGMENT_1>>17, /* brpn */
1, /* write-through */
1, /* cache-inhibited */
0, /* memory coherence */
@@ -609,13 +585,13 @@ BAT BAT0 =
BAT BAT1 =
{
{
- 0xC0000000>>17, /* bepi */
+ MMU_SEGMENT_2>>17, /* bepi */
BL_256M, /* bl */
1, /* vs */
1, /* vp */
},
{
- 0xC0000000>>17, /* brpn */
+ MMU_SEGMENT_2>>17, /* brpn */
1, /* w */
1, /* i (cache disabled) */
0, /* m */
@@ -635,7 +611,11 @@ BAT BAT2 =
0x00000000>>17, /* brpn */
0, /* w */
0, /* i */
+#ifdef __SMP__
1, /* m */
+#else
+ 0, /* m */
+#endif
0, /* g */
BPP_RW /* pp */
}
@@ -676,13 +656,13 @@ P601_BAT BAT0_601 =
P601_BAT BAT1_601 =
{
{
- 0xC0000000>>17, /* bepi */
+ MMU_SEGMENT_2>>17, /* bepi */
1,1,0, /* wim */
1, 0, /* vs, vp */
BPP_RW, /* pp */
},
{
- 0xC0000000>>17, /* brpn */
+ MMU_SEGMENT_2>>17, /* brpn */
1, /* v */
BL_8M, /* bl */
}
@@ -724,69 +704,24 @@ P601_BAT BAT3_601 =
* this will likely stay seperate from the pmac.
* -- Cort
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *prep_find_end_of_memory(void)
{
- extern RESIDUAL res;
- extern unsigned long resptr;
- int i, p;
- unsigned long h;
-
- /* copy residual data */
- if ( resptr )
- memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
- else
- /* clearing bss probably clears this but... */
- memset( &res, sizeof(RESIDUAL), 0 );
- _TotalMemory = res.TotalMemory;
+ int i;
- /* this really has nothing to do with the mmu_init() but is
- necessary for early setup -- Cort */
- if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- {
- _machine = _MACH_IBM;
- }
- else
- _machine = _MACH_Motorola;
-
- /* setup the hash table */
- if (_TotalMemory == 0 )
+ if (res.TotalMemory == 0 )
{
/*
* I need a way to probe the amount of memory if the residual
* data doesn't contain it. -- Cort
*/
printk("Ramsize from residual data was 0 -- Probing for value\n");
- _TotalMemory = 0x03000000;
- printk("Ramsize default to be %dM\n", _TotalMemory>>20);
+ res.TotalMemory = 0x03000000;
+ printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
}
-
-#if 0
- /* linux has trouble with > 64M ram -- Cort */
- if ( _TotalMemory > 0x04000000 /* 64M */ )
- {
- printk("Only using first 64M of ram.\n");
- _TotalMemory = 0x04000000;
- }
-#endif
-
- /* setup the bat2 mapping to cover physical ram */
- BAT2.batu.bl = 0x1; /* 256k mapping */
- for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
- h *= 2 )
- BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
- /*
- * Allow 64k of hash table for every 16MB of memory,
- * up to a maximum of 2MB.
- */
- for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
- ;
- Hash_size = h;
- Hash_mask = (h >> 6) - 1;
-
- /* align htab on a Hash_size boundry above _end[] */
- Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
- memset(Hash, Hash_size, 0 );
+ /* NOTE: everything below here is moving to mapin_ram() */
+
+
/*
* if this is a 601, we can only map sizes of 8M with the BAT's
* so we have to map what we can't map with the bats with the segregs
@@ -799,11 +734,11 @@ unsigned long *find_end_of_memory(void)
if ( _get_PVR() == 1 )
{
/* map in rest of ram with seg regs */
- if ( _TotalMemory > 0x01000000 /* 16M */)
+ if ( res.TotalMemory > 0x01000000 /* 16M */)
{
for (i = KERNELBASE+0x01000000;
- i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
- map_page(&init_task.tss, i, __pa(i),
+ i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
}
@@ -815,25 +750,21 @@ unsigned long *find_end_of_memory(void)
memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
memset(&BAT3_601, sizeof(BAT2), 0);
/* map all of ram for kernel with segregs */
- for (i = KERNELBASE; i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
+ for (i = KERNELBASE; i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
{
if ( i < (unsigned long)etext )
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
else
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
#endif /* MAP_RAM_WITH_SEGREGS */
- printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- _TotalMemory >> 20, Hash_size >> 10, Hash);
- return ((unsigned long *)_TotalMemory);
+ return (__va(res.TotalMemory));
}
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
/*
* Map in all of physical memory starting at KERNELBASE.
*/
@@ -847,17 +778,39 @@ static void mapin_ram()
int i;
unsigned long v, p, s, f;
- v = KERNELBASE;
- for (i = 0; i < phys_mem.n_regions; ++i) {
- p = phys_mem.regions[i].address;
- for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
- f = _PAGE_PRESENT | _PAGE_ACCESSED;
- if ((char *) v < _stext || (char *) v >= etext)
- f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
- map_page(&init_task.tss, v, p, f);
- v += PAGE_SIZE;
- p += PAGE_SIZE;
- }
+ if ( _machine == _MACH_Pmac )
+ {
+ v = KERNELBASE;
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ f = _PAGE_PRESENT | _PAGE_ACCESSED;
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+ else
+ /* On the powerpc, no user access forces R/W kernel access */
+ f |= _PAGE_USER;
+ map_page(&init_task, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
+ }
+ }
+ }
+ else /* prep */
+ {
+ /* setup the bat2 mapping to cover physical ram */
+ BAT2.batu.bl = 0x1; /* 256k mapping */
+ for ( f = 256*1024 /* 256k */ ;
+ (f <= res.TotalMemory) && (f <= 256*1024*1024);
+ f *= 2 )
+ BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+ /*
+ * let ibm get to the device mem from user mode since
+ * the X for them needs it right now -- Cort
+ */
+ if ( _machine == _MACH_IBM )
+ BAT0.batu.vp = BAT1.batu.vp = 1;
+
}
}
@@ -889,7 +842,7 @@ static void inherit_prom_translations()
for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
/* ignore stuff mapped down low */
- if (tp->virt < 0x10000000)
+ if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
continue;
/* map PPC mmu flags to linux mm flags */
f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
@@ -900,13 +853,12 @@ static void inherit_prom_translations()
p = tp->phys;
n = tp->size;
for (; n != 0; n -= PAGE_SIZE) {
- map_page(&init_task.tss, v, p, f);
+ map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
}
}
-#endif
/*
* Initialize the hash table and patch the instructions in head.S.
@@ -914,10 +866,29 @@ static void inherit_prom_translations()
static void hash_init(void)
{
int Hash_bits;
+ unsigned long h;
extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
hash_page_patch_C[];
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < (ulong)__pa(end_of_DRAM) / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* Find some memory for the hash table. */
+ if ( is_prep )
+ /* align htab on a Hash_size boundry above _end[] */
+ Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+ else /* pmac */
+ Hash = find_mem_piece(Hash_size, Hash_size);
+
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ __pa(end_of_DRAM) >> 20, Hash_size >> 10, Hash);
memset(Hash, 0, Hash_size);
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
@@ -943,8 +914,8 @@ static void hash_init(void)
* out from the data cache and invalidated in the instruction
* cache, on those machines with split caches.
*/
- store_cache_range((unsigned long) hash_page_patch_A,
- (unsigned long) (hash_page_patch_C + 1));
+ flush_icache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_C + 1));
}
@@ -958,71 +929,93 @@ static void hash_init(void)
void
MMU_init(void)
{
- end_of_DRAM = find_end_of_memory();
+ if ( _machine == _MACH_Pmac )
+ end_of_DRAM = pmac_find_end_of_memory();
+ else /* prep and chrp */
+ end_of_DRAM = prep_find_end_of_memory();
+
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#ifdef CONFIG_PMAC
- /* Force initial page tables */
- /* this done by INIT_TSS in processor.h on prep -- Cort */
- init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
/* Map in all of RAM starting at KERNELBASE */
mapin_ram();
- /* Copy mappings from the prom */
- inherit_prom_translations();
-#endif /* CONFIG_PMAC */
+ if ( _machine == _MACH_Pmac )
+ /* Copy mappings from the prom */
+ inherit_prom_translations();
}
static void *
MMU_get_page()
{
- void *p;
-
- if (mem_init_done) {
- p = (void *) __get_free_page(GFP_KERNEL);
- if (p == 0)
- panic("couldn't get a page in MMU_get_page");
- } else {
-#ifdef CONFIG_PREP
- mmu_pages_count++;
- if ( mmu_pages_count > MAX_MMU_PAGES )
- printk("out of mmu pages!\n");
- p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
- (mmu_pages_count+PAGE_SIZE));
-#endif
-#ifdef CONFIG_PMAC
- p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
-#endif
- }
- memset(p, 0, PAGE_SIZE);
- return p;
+ void *p;
+
+ if (mem_init_done) {
+ p = (void *) __get_free_page(GFP_KERNEL);
+ if (p == 0)
+ panic("couldn't get a page in MMU_get_page");
+ } else {
+ if ( is_prep || (_machine == _MACH_chrp) )
+ {
+ mmu_pages_count++;
+ if ( mmu_pages_count > MAX_MMU_PAGES )
+ printk("out of mmu pages!\n");
+ p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+ (mmu_pages_count+PAGE_SIZE));
+ }
+ else /* pmac */
+ {
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+ }
+ }
+ memset(p, 0, PAGE_SIZE);
+ return p;
}
-#ifdef CONFIG_PMAC
void *
ioremap(unsigned long addr, unsigned long size)
{
unsigned long p, end = addr + size;
+ /*
+ * BAT mappings on prep cover this already so don't waste
+ * space with it. -- Cort
+ */
+ if ( is_prep )
+ if ( ((addr >= 0xc0000000) && (end < (0xc0000000+(256<<20)))) ||
+ ((addr >= 0x80000000) && (end < (0x80000000+(256<<20)))) )
+ return (void *)addr;
for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
- map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
return (void *) addr;
}
-#endif
+
+extern void iounmap(unsigned long *addr)
+{
+ /*
+ * BAT mappings on prep cover this already so don't waste
+ * space with it. -- Cort
+ */
+ if ( is_prep )
+ if ( (((unsigned long)addr >= 0xc0000000) && ((unsigned long)addr < (0xc0000000+(256<<20)))) ||
+ (((unsigned long)addr >= 0x80000000) && ((unsigned long)addr < (0x80000000+(256<<20)))) )
+ return;
+ /* else unmap it */
+}
void
-map_page(struct thread_struct *tss, unsigned long va,
+map_page(struct task_struct *tsk, unsigned long va,
unsigned long pa, int flags)
{
pmd_t *pd;
pte_t *pg;
+
- if (tss->pg_tables == NULL) {
+ if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
- tss->pg_tables = (unsigned long *) MMU_get_page();
+ tsk->mm->pgd = (pgd_t *) MMU_get_page();
}
/* Use upper 10 bits of VA to index the first level map */
- pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+ pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
/* Need to allocate second-level table */
pg = (pte_t *) MMU_get_page();
@@ -1084,26 +1077,6 @@ flush_tlb_mm(struct mm_struct *mm)
}
}
-
-void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
- unsigned vsid;
-
- if ( vmaddr < TASK_SIZE) {
- /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
- flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(vma->vm_mm,vmaddr);
- }
- else
- {
- /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
- }
-}
-
-
/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
@@ -1113,15 +1086,10 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
void
flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
- start &= PAGE_MASK;
+ start &= PAGE_MASK;
for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
{
- /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
- start );*/
flush_hash_page(mm->context, start);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(mm,start);
}
}
@@ -1135,78 +1103,18 @@ void
mmu_context_overflow(void)
{
struct task_struct *tsk;
- int nr;
- printk(KERN_INFO "mmu_context_overflow\n");
- for (nr = 0; nr < NR_TASKS; ++nr) {
- tsk = task[nr];
- if (tsk && tsk->mm)
+ printk(KERN_DEBUG "mmu_context_overflow\n");
+ read_lock(&tasklist_lock);
+ for_each_task(tsk) {
+ if (tsk->mm)
tsk->mm->context = NO_CONTEXT;
}
+ read_unlock(&tasklist_lock);
flush_hash_segments(0x10, 0xffffff);
- _tlbia();
next_mmu_context = 0;
+ /* make sure current always has a context */
+ current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+ set_context(current->mm->context);
}
-#ifdef CONFIG_PREP
-/*
- * it's not a simple matter to get rid of these and switch to the
- * ones paul is using. it will take some time and thought -- Cort
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
-{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *slot;
- int flags = 0;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = VSID_FROM_CONTEXT(segment,mm->context);
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask /*<< 10*/);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- _tlbie(va); /* Clear TLB */
- if (_pte->r) flags |= _PAGE_ACCESSED;
- if (_pte->c) flags |= _PAGE_DIRTY;
- _pte->v = 0;
- return /*(flags)*/;
- }
- }
- }
- _tlbie(va);
- return /*(flags)*/;
-}
-#endif
-
-#include <asm/mmu.h>
-void print_mm_info(void)
-{
- struct _SEGREG s;
- long a;
- struct _BATU bu;
- struct _BATL bl;
- unsigned long i;
-
- for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
- {
- a = get_SR(i);
- memcpy(&s,&a,4);
- printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x %x\n",
- i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
- }
-
- asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
- printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
- bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
-}
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
new file mode 100644
index 000000000..5f34efcd2
--- /dev/null
+++ b/arch/ppc/pmac_defconfig
@@ -0,0 +1,274 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_NATIVE=y
+CONFIG_PMAC=y
+# CONFIG_PREP is not set
+CONFIG_MCOMMON=y
+# CONFIG_M601 is not set
+# CONFIG_M603 is not set
+# CONFIG_M604 is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_XMON=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# 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 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
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_QLOGIC_PMAC=m
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+CONFIG_NET_IPIP=m
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+CONFIG_INET_RARP=y
+CONFIG_PATH_MTU_DISCOVERY=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACE=y
+CONFIG_DEC_ELCP=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA 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=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+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=y
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+# CONFIG_CS4232 is not set
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CONFIG_LOWLEVEL_SOUND=y
+# CONFIG_ACI_MIXER is not set
+# CONFIG_AWE32_SYNTH is not set
+# CONFIG_AEDSP16 is not set
+CONFIG_AWACS=y
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
new file mode 100644
index 000000000..ea39e83ea
--- /dev/null
+++ b/arch/ppc/prep_defconfig
@@ -0,0 +1,250 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+CONFIG_MCOMMON=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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 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
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 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_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET 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=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+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
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds
new file mode 100644
index 000000000..1a51a4a7e
--- /dev/null
+++ b/arch/ppc/vmlinux.lds
@@ -0,0 +1,85 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+/* .init : { *(.init) } =0*/
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ *(.got1)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ .fixup : { *(.fixup) }
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
diff --git a/arch/sparc/ap1000/aplib.c b/arch/sparc/ap1000/aplib.c
index 55a778ed7..8bd67e530 100644
--- a/arch/sparc/ap1000/aplib.c
+++ b/arch/sparc/ap1000/aplib.c
@@ -455,7 +455,8 @@ static inline int aplib_poll(unsigned counter)
while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
tnet_check_completion();
- if (need_resched) break;
+ if (resched_needed())
+ break;
if (current->signal & ~current->blocked) break;
}
return 0;
diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c
index 84ef7f28e..3465e311b 100644
--- a/arch/sparc/ap1000/mpp.c
+++ b/arch/sparc/ap1000/mpp.c
@@ -28,7 +28,7 @@ static int last_task = 0;
void mpp_schedule(struct cap_request *req)
{
mpp_current_task = req->data[0];
- need_resched = 1;
+ resched_force();
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/ap1000/msc.c b/arch/sparc/ap1000/msc.c
index 242df954c..fc8aaf6e5 100644
--- a/arch/sparc/ap1000/msc.c
+++ b/arch/sparc/ap1000/msc.c
@@ -338,7 +338,7 @@ static inline void qbmful_interrupt(void)
#endif
MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
- need_resched = 1;
+ resched_force();
block_parallel_tasks = 1;
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/ap1000/tnet.c b/arch/sparc/ap1000/tnet.c
index 14a29ae7a..293be0d5b 100644
--- a/arch/sparc/ap1000/tnet.c
+++ b/arch/sparc/ap1000/tnet.c
@@ -613,7 +613,7 @@ void tnet_send_ip(int cid,struct sk_buff *skb)
static void reschedule(void)
{
- need_resched = 1;
+ resched_force();
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 69ed62422..fa8267db1 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.36 1997/06/17 03:54:47 davem Exp $
+# $Id: config.in,v 1.38 1997/09/04 01:54:33 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -53,9 +53,9 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
endmenu
@@ -146,6 +146,10 @@ fi
source fs/Config.in
mainmenu_option next_comment
+comment 'Watchdog'
+
+bool 'Software watchdog' CONFIG_SOFT_WATCHDOG
+mainmenu_option next_comment
comment 'Kernel hacking'
bool 'Kernel profiling support' CONFIG_PROFILE
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 80e114585..434d95d2b 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -49,6 +49,7 @@ SUN_FB_CREATOR=y
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
@@ -105,6 +106,7 @@ CONFIG_IP_MASQUERADE=y
CONFIG_IP_ALIAS=m
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
@@ -184,7 +186,7 @@ CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
@@ -207,6 +209,7 @@ CONFIG_AMIGA_PARTITION=y
CONFIG_UFS_FS=y
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
#
# Kernel hacking
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 3843a7aa8..b9c6495cf 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -53,8 +53,33 @@ device_scan(unsigned long mem_start))
}
};
if(cpu_ctr == 0) {
+ if (sparc_cpu_model == sun4d) {
+ scan = prom_getchild(prom_root_node);
+ for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
+ scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
+ int node = prom_getchild(scan);
+
+ prom_getstring(node, "device_type", node_str, sizeof(node_str));
+ if (strcmp(node_str, "cpu") == 0) {
+ prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
+ if (cpu_ctr < NCPUS) {
+ cpu_nds[cpu_ctr] = node;
+ linux_cpus[cpu_ctr].prom_node = node;
+ linux_cpus[cpu_ctr].mid = thismid;
+ }
+ prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
+ cpu_ctr, (unsigned long) node,
+ thismid);
+ cpu_ctr++;
+ }
+ }
+ }
+ if (cpu_ctr > NCPUS)
+ cpu_ctr = NCPUS;
+ }
+ if(cpu_ctr == 0) {
printk("No CPU nodes found, cannot continue.\n");
- /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
+ /* Probably a sun4e, Sun is trying to trick us ;-) */
halt();
}
printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 90965e26e..5742453ff 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $
+/* $Id: head.S,v 1.83 1997/08/28 11:10:39 jj Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -827,22 +827,18 @@ got_prop:
cmp %l1, 'c' ! We already know we are not
be 1f ! on a plain sun4 because of
- nop ! the check for 0x4000 in %o0
-
- cmp %l1, 'm' ! at start
+ ! the check for 0x4000 in %o0
+ cmp %l1, 'm' ! at start
be 1f
- nop
-
- cmp %l1, 'e'
+ cmp %l1, 'd'
+ be 1f
+ cmp %l1, 'e'
be no_sun4e_here ! Could be a sun4e.
nop
-
- b no_sun4u_here ! AIEEE, a V9 sun4u...
+ b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :))
nop
-
-1:
- set C_LABEL(cputypval), %l1
+1: set C_LABEL(cputypval), %l1
ldub [%l1 + 0x4], %l1
cmp %l1, 'm' ! Test for sun4d, sun4e ?
be sun4m_init
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 95eed6287..ff4a3f192 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.99 1997/07/17 02:20:13 davem Exp $
+/* $Id: process.c,v 1.100 1997/08/10 04:49:23 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -105,6 +105,8 @@ out:
/* This is being executed in task 0 'user space'. */
int cpu_idle(void *unused)
{
+ extern volatile int smp_commenced;
+
current->priority = -100;
while(1) {
/*
@@ -118,7 +120,8 @@ int cpu_idle(void *unused)
}
/* endless idle loop with no priority at all */
current->counter = -100;
- schedule();
+ if(!smp_commenced || resched_needed())
+ schedule();
}
}
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 732b3006d..933a5acfa 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -886,7 +886,7 @@ asmlinkage void syscall_trace(void)
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
current->tss.flags ^= MAGIC_CONSTANT;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
index d8d160114..8d46d487e 100644
--- a/arch/sparc/kernel/rtrap.S
+++ b/arch/sparc/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $
+/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
* rtrap.S: Return from Sparc trap low-level code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -65,12 +65,14 @@ C_LABEL(ret_trap_lockless_ipi):
wr %t_psr, 0x0, %psr
b ret_trap_kernel
- nop
+ mov 1, %o0
1:
+ ld [%curptr + AOFF_task_processor], %o1
ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
+ sll %o0, %o1, %o0
- cmp %g2, 0
+ andcc %g2, %o0, %g0
be signal_p
nop
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index fd5fa634e..fbb5578fa 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
+/* $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -722,7 +722,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
/* This happens to be SMP safe so no need to
* grab master kernel lock even in this case.
*/
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -773,7 +773,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
/* notify_parent() is SMP safe */
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index beef2df14..17931fd55 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -87,7 +87,7 @@ volatile int smp_process_available=0;
#define SMP_PRINTK(x)
#endif
-static volatile int smp_commenced = 0;
+volatile int smp_commenced = 0;
static char smp_buf[512];
@@ -558,7 +558,7 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
/* Reschedule call back. */
void smp_reschedule_irq(void)
{
- need_resched=1;
+ resched_force();
}
/* Running cross calls. */
@@ -623,7 +623,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
if(--current->counter < 0) {
current->counter = 0;
- need_resched = 1;
+ resched_force();
}
spin_lock(&ticker_lock);
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index ad9aa8953..8c3358a64 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
+/* $Id: srmmu.c,v 1.151 1997/08/28 11:10:54 jj Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -2103,14 +2103,18 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
sparc_iobase_vaddr = 0xfd000000; /* 16MB of IOSPACE on all sun4m's. */
physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */
- /* Find the number of contexts on the srmmu. */
- cpunode = prom_getchild(prom_root_node);
- num_contexts = 0;
- while((cpunode = prom_getsibling(cpunode)) != 0) {
- prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
- if(!strcmp(node_str, "cpu")) {
- num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8);
- break;
+ if (sparc_cpu_model == sun4d)
+ num_contexts = 65536; /* We now it is Viking */
+ else {
+ /* Find the number of contexts on the srmmu. */
+ cpunode = prom_getchild(prom_root_node);
+ num_contexts = 0;
+ while((cpunode = prom_getsibling(cpunode)) != 0) {
+ prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
+ if(!strcmp(node_str, "cpu")) {
+ num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8);
+ break;
+ }
}
}
@@ -2601,7 +2605,7 @@ __initfunc(static void init_swift(void))
}
/* turbosparc.S */
-extern void turbosparc_flush_cache_all();
+extern void turbosparc_flush_cache_all(void);
extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
static void poke_turbosparc(void)
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index b8cf06878..20b90a651 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.20 1997/07/11 11:05:29 jj Exp $
+# $Id: Makefile,v 1.22 1997/08/29 15:51:53 jj Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -17,7 +17,7 @@ LD = sparc64-linux-ld
NM = sparc64-linux-nm
AR = sparc64-linux-ar
RANLIB = sparc64-linux-ranlib
-ELF2AOUT64 = elf2aout64
+ELFTOAOUT = elftoaout
#
# Uncomment the first CFLAGS if you are doing kgdb source level
@@ -34,13 +34,21 @@ 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
+ifneq ($(CONFIG_SOLARIS_EMUL),n)
+ SUBDIRS += arch/sparc64/solaris
+endif
+
CORE_FILES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(CORE_FILES)
+ifeq ($(CONFIG_SOLARIS_EMUL),y)
+ CORE_FILES += arch/sparc64/solaris/solaris.o
+endif
+
LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
$(TOPDIR)/arch/sparc64/lib/lib.a
vmlinux.aout: vmlinux
- $(ELF2AOUT64) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
+ $(ELFTOAOUT) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
archclean:
rm -f $(TOPDIR)/vmlinux.aout
diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile
index ed3fc6cdb..4f2b9ead3 100644
--- a/arch/sparc64/boot/Makefile
+++ b/arch/sparc64/boot/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1997/07/18 06:26:30 ralf Exp $
+# $Id: Makefile,v 1.3 1997/08/29 11:08:34 davem Exp $
# Makefile for the Sparc64 boot stuff.
#
# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index fcbac5c1a..c3c438dc6 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
+# $Id: config.in,v 1.17 1997/09/04 01:54:43 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -43,6 +43,7 @@ else
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
+ define_bool CONFIG_PCI y
source drivers/sbus/char/Config.in
fi
@@ -57,10 +58,11 @@ if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL
fi
endmenu
@@ -83,6 +85,19 @@ fi
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+if [ "$CONFIG_PCI" = "y" ]; then
+ tristate 'Ultra/PCI IDE disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
+ if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+ dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+ dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+ define_bool CONFIG_IDE_CHIPSETS y
+ define_bool CONFIG_BLK_DEV_NS87415 y
+ fi
+fi
+
endmenu
if [ "$CONFIG_NET" = "y" ]; then
@@ -116,6 +131,21 @@ if [ "$CONFIG_SCSI" != "n" ]; then
bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+
+ if [ "$CONFIG_PCI" != "n" ]; then
+ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+ bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
+ dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
+ if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
+ int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+ fi
+ bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+ int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+ fi
+ fi
+
endmenu
fi
endmenu
@@ -141,6 +171,9 @@ if [ "$CONFIG_NET" = "y" ]; then
tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
tristate 'Sun QuadEthernet support' CONFIG_SUNQE
tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
+ if [ "$CONFIG_PCI" = "y" ]; then
+ tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ fi
# bool 'FDDI driver support' CONFIG_FDDI
# if [ "$CONFIG_FDDI" = "y" ]; then
# fi
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index c9c92b987..85958cd6e 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -29,6 +29,7 @@ CONFIG_SUN_KEYBOARD=y
CONFIG_SUN_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
+CONFIG_PCI=y
#
# SBUS Frame Buffer support
@@ -49,6 +50,7 @@ SUN_FB_CREATOR=y
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_SUN_OPENPROMFS=m
@@ -61,17 +63,26 @@ CONFIG_BINFMT_ELF32=y
CONFIG_BINFMT_AOUT32=y
CONFIG_BINFMT_JAVA=m
CONFIG_BINFMT_MISC=m
+CONFIG_SOLARIS_EMUL=m
#
# Floppy, IDE, and other block devices
#
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_LINEAR=m
CONFIG_MD_STRIPED=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_IDE=y
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_IDE_CHIPSETS=y
+CONFIG_BLK_DEV_NS87415=y
#
# Networking options
@@ -85,12 +96,13 @@ CONFIG_INET=y
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
#
# CONFIG_INET_PCTCP is not set
-# CONFIG_INET_RARP is not set
+CONFIG_INET_RARP=m
CONFIG_PATH_MTU_DISCOVERY=y
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
@@ -136,6 +148,12 @@ CONFIG_SCSI_CONSTANTS=y
#
CONFIG_SCSI_SUNESP=y
CONFIG_SCSI_QLOGICPTI=m
+CONFIG_SCSI_AIC7XXX=y
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+# CONFIG_AIC7XXX_PROC_STATS is not set
+CONFIG_AIC7XXX_RESET_DELAY=5
#
# Network device support
@@ -155,6 +173,7 @@ CONFIG_SUNLANCE=y
CONFIG_HAPPYMEAL=y
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
+CONFIG_DE4X5=y
#
# Filesystems
@@ -187,6 +206,7 @@ CONFIG_AMIGA_PARTITION=y
CONFIG_UFS_FS=m
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
#
# Kernel hacking
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index aecb9fd47..2b07a0e15 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
+# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -29,9 +29,10 @@ all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := process.o setup.o cpu.o idprom.o \
- systbls.o traps.o devices.o auxio.o ioport.o \
+ traps.o devices.o auxio.o ioport.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
- unaligned.o sys_sunos32.o sunos_ioctl32.o
+ unaligned.o sys_sunos32.o sunos_ioctl32.o \
+ central.o psycho.o ebus.o
OX_OBJS := sparc64_ksyms.o
ifdef SMP
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 00e5f2722..91365af85 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -3,15 +3,21 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
#include <asm/sbus.h>
+#include <asm/ebus.h>
+#include <asm/fhc.h>
/* Probe and map in the Auxiliary I/O register */
unsigned char *auxio_register;
@@ -31,9 +37,39 @@ __initfunc(void auxio_probe(void))
}
if (!sdev) {
+#ifdef CONFIG_PCI
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev = 0;
+ unsigned long led_auxio;
+
+ for_all_ebusdev(edev, ebus)
+ if (!strcmp(edev->prom_name, "auxio"))
+ break;
+
+ if (edev) {
+ if (check_region(edev->base_address[0],
+ sizeof(unsigned int))) {
+ prom_printf("%s: Can't get region %lx, %d\n",
+ __FUNCTION__, edev->base_address[0],
+ sizeof(unsigned int));
+ prom_halt();
+ }
+ request_region(edev->base_address[0],
+ sizeof(unsigned int), "LED auxio");
+
+ led_auxio = edev->base_address[0];
+ outl(0x01, led_auxio);
+ return;
+ }
+#endif
+ if(central_bus) {
+ auxio_register = NULL;
+ return;
+ }
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
}
+
prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
/* Map the register both read and write */
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 9ab2b7aca..ef41e3f7a 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -8,6 +8,9 @@
#define elf_check_arch(x) (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS))
+#define ELF_ET_DYN_BASE 0x60000000
+
+
#include <asm/processor.h>
#include <linux/module.h>
#include <linux/config.h>
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
new file mode 100644
index 000000000..817a8ecd3
--- /dev/null
+++ b/arch/sparc64/kernel/central.c
@@ -0,0 +1,129 @@
+/* $Id: central.c,v 1.4 1997/08/19 14:17:49 jj Exp $
+ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/fhc.h>
+
+struct linux_central *central_bus = NULL;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_central_ranges_init(int cnode, struct linux_central *central);
+extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+
+unsigned long central_probe(unsigned long memory_start)
+{
+ struct linux_prom_registers fpregs[6];
+ struct linux_fhc *fhc;
+ char namebuf[128];
+ int cnode, fnode, err;
+
+ printk("CENTRAL: ");
+ cnode = prom_finddevice("/central");
+ if(cnode == 0 || cnode == -1) {
+ printk("no central found.\n");
+ return memory_start;
+ }
+ prom_printf("CENTRAL: found central PROM node.\n");
+ printk("found central PROM node.\n");
+
+ /* Ok we got one, grab some memory for software state. */
+ memory_start = long_align(memory_start);
+ central_bus = (struct linux_central *) (memory_start);
+
+ prom_printf("CENTRAL: central_bus[%p] ", central_bus);
+ memory_start += sizeof(struct linux_central);
+ memory_start = long_align(memory_start);
+ fhc = (struct linux_fhc *)(memory_start);
+ memory_start += sizeof(struct linux_fhc);
+ memory_start = long_align(memory_start);
+
+ prom_printf("fhc[%p] ", fhc);
+
+ /* First init central. */
+ central_bus->child = fhc;
+ central_bus->prom_node = cnode;
+
+ prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
+ strcpy(central_bus->prom_name, namebuf);
+
+ prom_printf("init_central_ranges ");
+ prom_central_ranges_init(cnode, central_bus);
+
+ /* And then central's FHC. */
+ fhc->next = NULL;
+ fhc->parent = central_bus;
+ fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
+ if(fnode == 0 || fnode == -1) {
+ prom_printf("Critical error, central board lacks fhc.\n");
+ prom_halt();
+ }
+ fhc->prom_node = fnode;
+ prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
+ strcpy(fhc->prom_name, namebuf);
+
+ prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
+ prom_fhc_ranges_init(fnode, fhc);
+
+ /* Finally, map in FHC register set. (From the prtconf dumps
+ * I have seen on Ex000 boxes only the central ranges need to
+ * be applied to the fhc internal register set) -DaveM
+ */
+ err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
+ if(err == -1) {
+ prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+ prom_halt();
+ }
+ prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+ prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
+ "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
+ fpregs[0].which_io, fpregs[0].phys_addr,
+ fpregs[1].which_io, fpregs[1].phys_addr,
+ fpregs[2].which_io, fpregs[2].phys_addr,
+ fpregs[3].which_io, fpregs[3].phys_addr,
+ fpregs[4].which_io, fpregs[4].phys_addr,
+ fpregs[5].which_io, fpregs[5].phys_addr);
+ fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+ __va((((unsigned long)fpregs[0].which_io)<<32) |
+ (((unsigned long)fpregs[0].phys_addr)));
+ fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+ __va((((unsigned long)fpregs[1].which_io)<<32) |
+ (((unsigned long)fpregs[1].phys_addr)));
+ fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+ __va((((unsigned long)fpregs[2].which_io)<<32) |
+ (((unsigned long)fpregs[2].phys_addr)));
+ fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+ __va((((unsigned long)fpregs[3].which_io)<<32) |
+ (((unsigned long)fpregs[3].phys_addr)));
+ fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+ __va((((unsigned long)fpregs[4].which_io)<<32) |
+ (((unsigned long)fpregs[4].phys_addr)));
+ fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+ __va((((unsigned long)fpregs[5].which_io)<<32) |
+ (((unsigned long)fpregs[5].phys_addr)));
+ prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
+ fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
+ fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
+ fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
+
+ prom_printf("CENTRAL: reading FHC_ID register... ");
+ err = fhc->fhc_regs.pregs->fhc_id;
+ prom_printf("VALUE[%x]\n", err);
+ printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+ ((err & FHC_ID_VERS) >> 28),
+ ((err & FHC_ID_PARTID) >> 12),
+ ((err & FHC_ID_MANUF) >> 1));
+
+ return memory_start;
+}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 2c96a83e9..d009f39d8 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -46,8 +46,13 @@ struct cpu_iu_info linux_sparc_chips[] = {
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#ifdef __SMP__
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#else
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+#endif
unsigned int fsr_storage;
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 9327058a8..24ca3ff10 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -17,13 +17,14 @@ struct prom_cpuinfo linux_cpus[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
+extern unsigned long central_probe(unsigned long);
__initfunc(unsigned long
device_scan(unsigned long mem_start))
{
char node_str[128];
int nd, prom_node_cpu, thismid;
- int cpu_nds[NCPUS]; /* One node for each cpu */
+ int cpu_nds[NR_CPUS]; /* One node for each cpu */
int cpu_ctr = 0;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
@@ -43,11 +44,14 @@ device_scan(unsigned long mem_start))
if(strcmp(node_str, "cpu") == 0) {
cpu_nds[cpu_ctr] = scan;
linux_cpus[cpu_ctr].prom_node = scan;
- prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+ prom_getproperty(scan, "upa-portid",
+ (char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
cpu_ctr, (unsigned) scan,
thismid);
+ printk("Found CPU %d <node=%08x,mid=%d>\n",
+ cpu_ctr, (unsigned) scan, thismid);
cpu_ctr++;
}
};
@@ -62,5 +66,5 @@ device_scan(unsigned long mem_start))
linux_num_cpus = cpu_ctr;
cpu_probe();
- return mem_start;
+ return central_probe(mem_start);
}
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
index b034ef407..04efb1cec 100644
--- a/arch/sparc64/kernel/dtlb_miss.S
+++ b/arch/sparc64/kernel/dtlb_miss.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
+/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
* dtlb_miss.S: Data TLB miss code, this is included directly
* into the trap table.
*
@@ -62,7 +62,7 @@
/*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
/*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables
/*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
- /*0x4c*/ andcc %g3, 0x80, %g0 ! Slick trick...
+ /*0x4c*/ andcc %g3, 0x400, %g0 ! Slick trick...
/*0x50*/ sllx %g1, 32, %g1 ! Move high bits up
/*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO
/*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page?
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 2cf372ca9..55e86c887 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.12 1997/05/18 10:04:43 davem Exp $
+/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
@@ -36,17 +36,17 @@
/* ICACHE line 3 */
/*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
+ /*0x48*/ mov TLB_SFSR, %g5 ! read SFSR
+ /*0x4c*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
+ /*0x50*/ and %g5, 0x10, %g5 ! context bit
+ /*0x54*/ or %g4, %g5, %g4 ! for prot trap
+1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x5c*/ membar #Sync ! Synchronize
/* ICACHE line 4 */
- /*0x60*/ nop
- /*0x64*/ nop
- /*0x68*/ nop
+ /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x68*/ retry ! Trap return
/*0x6c*/ nop
/*0x70*/ nop
/*0x74*/ nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
new file mode 100644
index 000000000..f484cfef8
--- /dev/null
+++ b/arch/sparc64/kernel/ebus.c
@@ -0,0 +1,326 @@
+/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+#undef DEBUG_FILL_EBUS_DEV
+
+struct linux_ebus *ebus_chain = 0;
+
+extern void prom_ebus_ranges_init(struct linux_ebus *);
+extern unsigned long pci_console_init(unsigned long memory_start);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+
+extern unsigned int psycho_irq_build(unsigned int full_ino);
+
+static inline unsigned long
+ebus_alloc(unsigned long *memory_start, size_t size)
+{
+ unsigned long mem;
+
+ *memory_start = (*memory_start + 7) & ~(7);
+ mem = *memory_start;
+ *memory_start += size;
+ return mem;
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
+{
+ int regs[PROMREG_MAX];
+ int irqs[PROMREG_MAX];
+ char lbuf[128];
+ int i, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ dev->num_addrs = len / sizeof(regs[0]);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ if (regs[i] >= dev->parent->num_addrs) {
+ prom_printf("UGH: property for %s was %d, need < %d\n",
+ dev->prom_name, len, dev->parent->num_addrs);
+ panic(__FUNCTION__);
+ }
+ dev->base_address[i] = dev->parent->base_address[regs[i]];
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("child '%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+}
+
+__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+ unsigned long memory_start))
+{
+ struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_ebus_child *child;
+ int irqs[PROMINTR_MAX];
+ char lbuf[128];
+ int i, n, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ if (len % sizeof(struct linux_prom_registers)) {
+ prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+ dev->prom_name, len,
+ (int)sizeof(struct linux_prom_registers));
+ panic(__FUNCTION__);
+ }
+ dev->num_addrs = len / sizeof(struct linux_prom_registers);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ n = (regs[i].which_io - 0x10) >> 2;
+
+ dev->base_address[i] = dev->parent->self->base_address[n];
+ dev->base_address[i] += (unsigned long)regs[i].phys_addr;
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("'%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+ if ((node = prom_getchild(node))) {
+ dev->children = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = dev->children;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+
+ while ((node = prom_getsibling(node))) {
+ child->next = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = child->next;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+ }
+ }
+
+ return memory_start;
+}
+
+__initfunc(unsigned long ebus_init(unsigned long memory_start,
+ unsigned long memory_end))
+{
+ struct linux_prom_pci_registers regs[PROMREG_MAX];
+ struct linux_pbm_info *pbm;
+ struct linux_ebus_device *dev;
+ struct linux_ebus *ebus;
+ struct pci_dev *pdev;
+ struct pcidev_cookie *cookie;
+ char lbuf[128];
+ unsigned long addr, *base;
+ unsigned short pci_command;
+ int nd, len, ebusnd;
+ int reg, rng, nreg;
+ int num_ebus = 0;
+
+ if (!pcibios_present())
+ return memory_start;
+
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev) {
+ printk("ebus: No EBus's found.\n");
+ return memory_start;
+ }
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus_chain = ebus = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus->next = 0;
+
+ while (ebusnd) {
+ printk("ebus%d:\n", num_ebus);
+
+ prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+ ebus->prom_node = ebusnd;
+ strcpy(ebus->prom_name, lbuf);
+
+ ebus->self = pdev;
+ ebus->parent = pbm = cookie->pbm;
+
+ /* Enable BUS Master. */
+ pcibios_read_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, pci_command);
+
+ len = prom_getproperty(ebusnd, "reg", (void *)regs,
+ sizeof(regs));
+ if (len == 0 || len == -1) {
+ prom_printf("%s: can't find reg property\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+ nreg = len / sizeof(struct linux_prom_pci_registers);
+
+ base = &ebus->self->base_address[0];
+ for (reg = 0; reg < nreg; reg++) {
+ if (!(regs[reg].phys_hi & 0x03000000))
+ continue;
+
+ for (rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp =
+ &pbm->pbm_ranges[rng];
+
+ if ((rp->child_phys_hi ^ regs[reg].phys_hi)
+ & 0x03000000)
+ continue;
+
+ addr = (u64)regs[reg].phys_lo;
+ addr += (u64)regs[reg].phys_mid << 32UL;
+ addr += (u64)rp->parent_phys_lo;
+ addr += (u64)rp->parent_phys_hi << 32UL;
+ *base++ = (unsigned long)__va(addr);
+
+ break;
+ }
+ }
+
+ prom_ebus_ranges_init(ebus);
+
+ nd = prom_getchild(ebusnd);
+ ebus->devices = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+
+ dev = ebus->devices;
+ dev->next = 0;
+ dev->children = 0;
+ dev->parent = ebus;
+ memory_start = fill_ebus_device(nd, dev, memory_start);
+
+ while ((nd = prom_getsibling(nd))) {
+ dev->next = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+
+ dev = dev->next;
+ dev->next = 0;
+ dev->children = 0;
+ dev->parent = ebus;
+ memory_start = fill_ebus_device(nd, dev, memory_start);
+ }
+
+ for (pdev = pdev->next; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev)
+ break;
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus->next = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus = ebus->next;
+ ebus->next = 0;
+ ++num_ebus;
+ }
+
+ memory_start = pci_console_init(memory_start);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+ openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+ rtc_init();
+#endif
+#ifdef CONFIG_SPARCAUDIO
+ sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+ bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+ if (sparc_cpu_model == sun4u)
+ auxio_probe();
+#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+ extern void clock_probe(void);
+
+ sun4u_start_timers();
+ clock_probe();
+ }
+#endif
+ return memory_start;
+}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 425c2d873..a6e2d6da7 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,9 +1,9 @@
-/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
+/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -17,6 +17,7 @@
#include <asm/page.h>
#include <asm/signal.h>
#include <asm/pgtable.h>
+#include <asm/processor.h>
/* #define SYSCALL_TRACING */
@@ -50,41 +51,39 @@ sparc64_dtlb_prot_catch:
bgu,a,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1f
mov 1, %o2
+ .align 32
sparc64_dtlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-
cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
be,a,pt %xcc, 2f
mov 1, %g4
wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+
rdpr %tl, %g3
ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
-
cmp %g3, 1
bgu,pn %icc, winfix_trampoline
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
+
clr %o2
1: srlx %l5, PAGE_SHIFT, %o1
add %sp, STACK_BIAS + REGWIN_SZ, %o0
-
call do_sparc64_fault
sllx %o1, PAGE_SHIFT, %o1
b,pt %xcc, rtrap
clr %l6
- nop
- nop
- nop
- nop
-
+ .align 32
sparc64_itlb_refbit_catch:
srlx %g5, 9, %g4
and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
@@ -95,17 +94,21 @@ sparc64_itlb_refbit_catch:
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tpc, %g5
+ sethi %hi(109f), %g7
b,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
b,pt %xcc, 1b
clr %o2
+
+ .align 32
2: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
-
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
retry
+
+ .align 32
3: sllx %g4, 63, %g4 ! _PAGE_VALID
or %g5, _PAGE_ACCESSED, %g5
or %g5, %g4, %g5
@@ -113,24 +116,33 @@ sparc64_itlb_refbit_catch:
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
retry
+#define FPDIS_OFF (((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))
/* This is trivial with the new code... */
.align 32
.globl do_fpdis
do_fpdis:
- wr %g0, FPRS_FEF, %fprs
- ldx [%g6 + AOFF_task_flags], %g2
- sethi %hi(0x00100000), %g4 ! XXX PF_USEDFPU
- andcc %g2, %g4, %g0
-
- bne,a,pt %xcc, fpload_fromkstk
- sethi %hi((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
- fzero %f0
- fzero %f2
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group
+ sethi %hi(TSTATE_PEF), %g4 ! IEU0
+ sethi %hi(FPDIS_OFF), %g3 ! IEU1
+ wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles
+ andcc %g5, SPARC_FLAG_USEDFPU, %g0 ! IEU1 Group
+ or %g3, %lo(FPDIS_OFF), %g2 ! IEU0
+ sethi %hi(empty_zero_page), %g1 ! IEU0 Group
+ add %g6, %g2, %g2 ! IEU1
+ be,a,pn %icc, 1f ! CTI
+ clr %g7 ! IEU0 Group
+ add %g2, 0x100, %g1 ! IEU1
+ ldx [%g2 + 0x108], %g7 ! Load
+1: andcc %g5, SPARC_FLAG_USEDFPUL, %g0 ! IEU1 Group
+ bne,pn %icc, 2f ! CTI
+ fzero %f0 ! FPA
+ andcc %g5, SPARC_FLAG_USEDFPUU, %g0 ! IEU1 Group
+ bne,pn %icc, 1f ! CTI
+ fzero %f2 ! FPA
faddd %f0, %f2, %f4
fmuld %f0, %f2, %f6
faddd %f0, %f2, %f8
fmuld %f0, %f2, %f10
-
faddd %f0, %f2, %f12
fmuld %f0, %f2, %f14
faddd %f0, %f2, %f16
@@ -139,7 +151,6 @@ do_fpdis:
fmuld %f0, %f2, %f22
faddd %f0, %f2, %f24
fmuld %f0, %f2, %f26
-
faddd %f0, %f2, %f28
fmuld %f0, %f2, %f30
faddd %f0, %f2, %f32
@@ -148,54 +159,92 @@ do_fpdis:
fmuld %f0, %f2, %f38
faddd %f0, %f2, %f40
fmuld %f0, %f2, %f42
-
faddd %f0, %f2, %f44
fmuld %f0, %f2, %f46
- ldx [%g6 + AOFF_task_flags], %g2
faddd %f0, %f2, %f48
fmuld %f0, %f2, %f50
- or %g2, %g4, %g2
faddd %f0, %f2, %f52
fmuld %f0, %f2, %f54
-
- stx %g2, [%g6 + AOFF_task_flags]
faddd %f0, %f2, %f56
- sethi %hi(empty_zero_page), %g3
fmuld %f0, %f2, %f58
-
- faddd %f0, %f2, %f60
- ldx [%g3], %fsr ! wheee, empty_zero_page
+ b,pt %xcc, fpdis_exit2
+ faddd %f0, %f2, %f60
+1: mov SECONDARY_CONTEXT, %g3
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ flush %g2
+ wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ membar #StoreLoad | #LoadLoad
+ ldda [%g2 + 0x080] %asi, %f32
+ ldda [%g2 + 0x0c0] %asi, %f48
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
b,pt %xcc, fpdis_exit
- wr %g0, 0, %gsr
-
-fpload_fromkstk:
- or %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
- add %g6, %g2, %g2
+ membar #Sync
+2: andcc %g5, SPARC_FLAG_USEDFPUU, %g0
+ bne,pt %icc, 3f
+ fzero %f32
mov SECONDARY_CONTEXT, %g3
+ fzero %f34
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ flush %g2
+ wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ membar #StoreLoad | #LoadLoad
+ ldda [%g2 + 0x000] %asi, %f0
+ ldda [%g2 + 0x040] %asi, %f16
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ b,pt %xcc, fpdis_exit
+ membar #Sync
+3: mov SECONDARY_CONTEXT, %g3
+ ldxa [%g3] ASI_DMMU, %g5
stxa %g0, [%g3] ASI_DMMU
flush %g2
wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
membar #StoreLoad | #LoadLoad
-
ldda [%g2 + 0x000] %asi, %f0
ldda [%g2 + 0x040] %asi, %f16
ldda [%g2 + 0x080] %asi, %f32
ldda [%g2 + 0x0c0] %asi, %f48
- ldx [%g2 + 0x100], %fsr
- ldx [%g2 + 0x108], %g2
membar #Sync
- wr %g2, 0, %gsr
fpdis_exit:
+ stxa %g5, [%g3] ASI_DMMU
+ flush %g2
+fpdis_exit2:
+ wr %g7, 0, %gsr
+ ldx [%g1], %fsr
rdpr %tstate, %g3
- sethi %hi(TSTATE_PEF), %g4
or %g3, %g4, %g3 ! anal...
wrpr %g3, %tstate
+ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
retry
-#ifdef __SMP__
- /* Note check out head.h, this code isn't even used for UP,
- * for SMP things will be different. In particular the data
- * registers for cross calls will be:
+ /* The registers for cross calls will be:
*
* DATA 0: [low 32-bits] Address of function to call, jmp to this
* [high 32-bits] MMU Context Argument 0, place in %g5
@@ -205,11 +254,17 @@ fpdis_exit:
* With this method we can do most of the cross-call tlb/cache
* flushing very quickly.
*/
+ .data
+ .align 8
+ .globl ivec_spurious_cookie
+ivec_spurious_cookie: .xword 0
+
+ .text
.align 32
- .globl do_ivec, do_ivec_return
+ .globl do_ivec
do_ivec:
- ldxa [%g0] ASI_INTR_RECEIVE, %g1
- andcc %g1, 0x20, %g0
+ ldxa [%g0] ASI_INTR_RECEIVE, %g5
+ andcc %g5, 0x20, %g0
be,pn %xcc, do_ivec_return
mov 0x40, %g2
@@ -223,39 +278,45 @@ do_ivec:
sllx %g3, 3, %g3
ldx [%g1 + %g3], %g2
brz,pn %g2, do_ivec_spurious
- nop
+ sethi %hi(0x80000000), %g5
+
+ or %g2, %g5, %g2
+ stx %g2, [%g1 + %g3]
/* No branches, worse case we don't know about this interrupt
* yet, so we would just write a zero into the softint register
* which is completely harmless.
*/
wr %g2, 0x0, %set_softint
-
do_ivec_return:
- /* Acknowledge the UPA */
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
retry
do_ivec_xcall:
srlx %g3, 32, %g5
add %g2, 0x10, %g2
- sra %g3, 0, %g3
+ srl %g3, 0, %g3
ldxa [%g2] ASI_UDB_INTR_R, %g6
add %g2, 0x10, %g2
+ ldxa [%g2] ASI_UDB_INTR_R, %g7
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
jmpl %g3, %g0
- ldxa [%g2] ASI_UDB_INTR_R, %g7
+ membar #Sync
do_ivec_spurious:
+ srl %g3, 3, %g3
+ sethi %hi(ivec_spurious_cookie), %g2
+ stx %g3, [%g2 + %lo(ivec_spurious_cookie)]
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pstate, %g5
+ wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call report_spurious_ivec
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
-#endif /* __SMP__ */
.globl getcc, setcc
getcc:
@@ -359,8 +420,9 @@ floppy_overrun:
floppy_dosoftint:
rdpr %pil, %g2
wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
mov 11, %o0
mov 0, %o1
@@ -373,10 +435,8 @@ floppy_dosoftint:
#endif /* CONFIG_BLK_DEV_FD */
/* XXX Here is stuff we still need to write... -DaveM XXX */
- .globl indirect_syscall, netbsd_syscall, solaris_syscall
-indirect_syscall:
+ .globl netbsd_syscall
netbsd_syscall:
-solaris_syscall:
retl
nop
@@ -386,8 +446,9 @@ do_mna:
cmp %g3, 1
bgu,a,pn %icc, winfix_mna
rdpr %tpc, %g3
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
@@ -573,14 +634,8 @@ sys_fork:
sys_vfork: mov SIGCHLD, %o0
clr %o1
sys_clone: mov %o7, %l5
-/*???*/ save %sp, -REGWIN_SZ, %sp
- flushw
-/*???*/ restore %g0, %g0, %g0
- rdpr %cwp, %o4
add %sp, STACK_BIAS + REGWIN_SZ, %o2
-
movrz %o1, %fp, %o1
- stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
call do_fork
mov %l5, %o7
#ifdef __SMP__
@@ -611,9 +666,9 @@ linux_sparc_syscall:
cmp %g1, NR_SYSCALLS ! IEU1 Group
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
mov %i0, %o0 ! IEU0
- sll %g1, 3, %l4 ! IEU0 Group
+ sll %g1, 2, %l4 ! IEU0 Group
mov %i1, %o1 ! IEU1
- ldx [%l7 + %l4], %l7 ! Load
+ lduw [%l7 + %l4], %l7 ! Load
syscall_is_too_hard:
mov %i2, %o2 ! IEU0 Group
ldx [%curptr + AOFF_task_flags], %l5 ! Load
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 4daf30e21..e10480454 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
+/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -15,118 +15,127 @@
#define FPUREG_SZ ((64 * 4) + (2 * 8))
#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
TRACEREG_SZ-REGWIN_SZ)
+#define FPU_OFF (STACK_BIAS + REGWIN_SZ + TRACEREG_SZ)
+
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
.text
.align 32
+etrap_priv: or %g1, %g3, %g1 ! IEU0 Group
+ rd %fprs, %g3 ! Single Group+4bubbles
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU0 Group
+ andcc %g3, FPRS_FEF, %g0 ! IEU1
+ add %g2, REGWIN_SZ + TRACEREG_SZ - FPUREG_SZ, %g3 ! IEU0 Group
+ be,pt %icc, 1f ! CTI
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ andn %g3, (64 - 1), %g3 ! IEU0 Group
+ ba,pt %xcc, 1f ! CTI
+ sub %g3, REGWIN_SZ + TRACEREG_SZ, %g2 ! IEU0 Group
+
+ .align 32
.globl etrap, etrap_irq, etraptl1
-etrap: rdpr %pil, %g2
-etrap_irq: rdpr %tstate, %g1
- sllx %g2, 20, %g2
- or %g1, %g2, %g1
- andcc %g1, TSTATE_PRIV, %g0
- bne,pn %xcc, etrap_maybe_fpu
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
- sethi %hi(TASK_REGOFF), %g2
-
- or %g2, %lo(TASK_REGOFF), %g2
- add %g6, %g2, %g2
-etrap_maybe_fpu:rd %fprs, %g3
- brnz,pn %g3, etrap_save_fpu
- st %g0, [%g2 + REGWIN_SZ + PT_V9_FPRS]
-etrap_after_fpu:rdpr %tpc, %g3
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
- rdpr %tnpc, %g1
-
- stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC]
- rd %y, %g3
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]
- st %g3, [%g2 + REGWIN_SZ + PT_V9_Y]
- save %g2, -STACK_BIAS, %sp ! The ordering here is
- rdpr %pstate, %g1 ! critical, see winfixup
- bne,pn %xcc, 2f
- rdpr %canrestore, %g3
-
- rdpr %wstate, %g2
- wrpr %g0, 7, %cleanwin
- wrpr %g0, 0, %canrestore
- sll %g2, 3, %g2
- wrpr %g3, 0, %otherwin
- wrpr %g2, 0, %wstate
- wr %g0, ASI_DMMU, %asi
- ldxa [%g0 + PRIMARY_CONTEXT] %asi, %g2
-
- stxa %g0, [%g0 + PRIMARY_CONTEXT] %asi
- stxa %g2, [%g0 + SECONDARY_CONTEXT] %asi
- flush %g6
-2: wrpr %g0, 0x0, %tl
- or %g1, 0, %l1
- add %g4, 0, %l4
- or %g5, 0, %l5
- add %g7, 0, %l2
-
- or %g6, 0, %l6
- wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate
- stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
- stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
- stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
- stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
- stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]
-
- stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
- stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
- stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
- stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
- stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
- stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
- sethi %uhi(PAGE_OFFSET), %g4
- stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
-
- stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
- sllx %g4, 32, %g4
- stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
- wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate
- jmpl %l2 + 0x4, %g0
- mov %l6, %g6
-etrap_save_fpu: and %g3, FPRS_FEF, %g3
- brz,pn %g3, 2f
-
- nop
- be,a,pt %xcc, 3f
- add %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
- wr %g0, ASI_BLK_P, %asi
- add %g2, ((TRACEREG_SZ+REGWIN_SZ)-FPUREG_SZ), %g2
- andn %g2, (64 - 1), %g2
-1: st %g3, [%g2 - 0x4 /*REGWIN_SZ + PT_V9_FPRS*/]
- rd %gsr, %g3
-
- stx %fsr, [%g2 + 0x100]
- stx %g3, [%g2 + 0x108]
- membar #StoreStore | #LoadStore
- stda %f0, [%g2 + 0x000] %asi
- stda %f16, [%g2 + 0x040] %asi
- stda %f32, [%g2 + 0x080] %asi
- stda %f48, [%g2 + 0x0c0] %asi
- membar #Sync
-
- sub %g2, (TRACEREG_SZ + REGWIN_SZ), %g2
-2: b,pt %xcc, etrap_after_fpu
- wr %g0, 0, %fprs
-3: /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */
- mov SECONDARY_CONTEXT, %g3
- stxa %g0, [%g3] ASI_DMMU
- flush %g2
- wr %g0, ASI_BLK_S, %asi
- nop
+etrap: rdpr %pil, %g2 ! Single Group
+etrap_irq: rdpr %tstate, %g1 ! Single Group
+ sllx %g2, 20, %g3 ! IEU0 Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ bne,pn %xcc, etrap_priv ! CTI
+ sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
+ or %g1, %g3, %g1 ! IEU1
+ or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
+ add %g6, %g2, %g2 ! IEU0 Group
+1: rdpr %tpc, %g3 ! Single Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
+ rdpr %tnpc, %g1 ! Single Group
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
+ rd %y, %g3 ! Single Group+4bubbles
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
+ st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
+ save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
+ rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
+ bne,pn %xcc, 2f ! CTI Group
+ sethi %hi(TSTATE_PEF), %l2 ! IEU0
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
+ rdpr %canrestore, %g3 ! Single Group+4bubbles
+ rdpr %wstate, %g2 ! Single Group+4bubbles
+ wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
+ wrpr %g0, 0, %canrestore ! Single Group+4bubbles
+ sll %g2, 3, %g2 ! IEU0 Group
+ mov SECONDARY_CONTEXT, %l5 ! IEU1
+ wrpr %g3, 0, %otherwin ! Single Group+4bubbles
+ wrpr %g2, 0, %wstate ! Single Group+4bubbles
+ rdpr %tstate, %l3 ! Single Group
+ ldxa [%l4] ASI_DMMU, %g2 ! Load Group
+ stxa %g0, [%l4] ASI_DMMU ! Store Group
+ stxa %g2, [%l5] ASI_DMMU ! Store Group
+ flush %g6 ! Single Group+9bubbles
+ andcc %l3, %l2, %g0 ! IEU1 Group
+ be,a,pt %icc, 6f ! CTI
+ st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ rd %fprs, %l0 ! Single Group+4bubbles
+ andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group
+ stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
+ or %l4, %l0, %l4 ! IEU0 Group
+ ba,pt %xcc, 3f ! CTI
+ st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store
+2: rd %fprs, %l0 ! Single Group+4bubbles
+ andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
+ stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
+3: rd %gsr, %l7 ! Single Group+4bubbles
+ cmp %l0, FPRS_FEF ! IEU1 Group
+ be,pn %icc, 6f ! CTI
+ stx %l7, [%sp + FPU_OFF + 0x108] ! Store
+ wr %g0, ASI_BLK_P, %asi ! Singe Group+4bubbles
+ andcc %l0, FPRS_DL, %g0 ! IEU1 Group
+ be,pn %icc, 4f ! CTI
+ membar #StoreStore | #LoadStore ! Memory
+ stda %f0, [%sp + FPU_OFF + 0x000] %asi ! Store Group
+ stda %f16, [%sp + FPU_OFF + 0x040] %asi ! Store Group
+ andcc %l0, FPRS_DU, %g0 ! IEU1
+ be,pn %icc, 5f ! CTI
+ nop ! IEU0 Group
+4: stda %f32, [%sp + FPU_OFF + 0x080] %asi ! Store Group
+ stda %f48, [%sp + FPU_OFF + 0x0c0] %asi ! Store Group
+5: membar #Sync ! Memory
+6: wr %g0, 0x0, %fprs ! Single Group+4bubbles
+ wrpr %g0, 0x0, %tl ! Single Group+4bubbles
+ mov %g1, %l1 ! IEU0 Group
+ mov %g4, %l4 ! IEU1
+ mov %g5, %l5 ! IEU0 Group
+ mov %g7, %l2 ! IEU1
+ mov %g6, %l6 ! IEU0 Group
+ wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
+ sllx %g4, 32, %g4 ! IEU0
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
+ wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ jmpl %l2 + 0x4, %g0 ! CTI Group
+ mov %l6, %g6 ! IEU0
- b,pt %xcc, 1b
- mov FPRS_FEF, %g3
- nop
-etraptl1: rdpr %tstate, %g1
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
- ba,pt %xcc, etrap_maybe_fpu
- andcc %g1, TSTATE_PRIV, %g0
- nop
+etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles
+ ba,pt %xcc, etrap_priv ! CTI Group
+ clr %g3 ! IEU0
#undef TASK_REGOFF
#undef FPUREG_SZ
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 0ed975aff..43f950b25 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
+/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
#include <asm/processor.h>
#include <asm/lsu.h>
#include <asm/head.h>
+#include <asm/ttable.h>
/* This section from from _start to sparc64_boot_end should fit into
* 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
@@ -89,6 +90,28 @@ sparc64_boot:
*/
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+#ifdef __SMP__
+ /* Ugly but necessary... */
+ sethi %hi(KERNBASE), %g7
+ sethi %hi(sparc64_cpu_startup), %g5
+ or %g5, %lo(sparc64_cpu_startup), %g5
+ sub %g5, %g7, %g5
+ sethi %hi(sparc64_cpu_startup_end), %g6
+ or %g6, %lo(sparc64_cpu_startup_end), %g6
+ sub %g6, %g7, %g6
+ sethi %hi(smp_trampoline), %g3
+ or %g3, %lo(smp_trampoline), %g3
+ sub %g3, %g7, %g3
+1: ldx [%g5], %g1
+ stx %g1, [%g3]
+ membar #StoreStore
+ flush %g3
+ add %g5, 8, %g5
+ cmp %g5, %g6
+ blu,pt %xcc, 1b
+ add %g3, 8, %g3
+#endif
+
create_mappings:
/* %g5 holds the tlb data */
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -340,7 +363,7 @@ setup_tba:
mov 0x40, %g2 /* INTR data 0 register */
/* Ok, we're done setting up all the state our trap mechanims needs,
- * now get back into normal globals and let the PROM know what it up.
+ * now get back into normal globals and let the PROM know what is up.
*/
wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate
@@ -374,6 +397,7 @@ bootup_kernel_stack:
! 0x0000000000408000
#include "ttable.S"
+#include "systbls.S"
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 81eb45e42..af88ca4b6 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
+/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -23,6 +23,7 @@
#include <linux/vt.h>
#include <linux/fs.h>
#include <linux/fd.h>
+#include <linux/if_ppp.h>
#include <asm/types.h>
#include <asm/uaccess.h>
@@ -102,6 +103,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
return -EFAULT;
+
ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq);
ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
if (!ifc.ifc_buf) return -ENOMEM;
@@ -145,7 +147,8 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
unsigned long old_fs;
int err;
- if (cmd == SIOCSIFMAP) {
+ switch (cmd) {
+ case SIOCSIFMAP:
if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) ||
__get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
__get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
@@ -154,9 +157,20 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
__get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
__get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
return -EFAULT;
- } else {
+ break;
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
+ if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+ return -EFAULT;
+ ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+ if (!ifr.ifr_data)
+ return -EAGAIN;
+ break;
+ default:
if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
return -EFAULT;
+ break;
}
old_fs = get_fs();
set_fs (KERNEL_DS);
@@ -177,6 +191,25 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32)))
return -EFAULT;
break;
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
+ {
+ u32 data;
+ int len;
+
+ __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data));
+ if(cmd == SIOCGPPPVER)
+ len = strlen(PPP_VERSION) + 1;
+ else if(cmd == SIOCGPPPCSTATS)
+ len = sizeof(struct ppp_comp_stats);
+ else
+ len = sizeof(struct ppp_stats);
+
+ if (copy_to_user((char *)A(data), ifr.ifr_data, len))
+ return -EFAULT;
+ break;
+ }
case SIOCGIFMAP:
if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) ||
__put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
@@ -481,6 +514,74 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
return ret;
}
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ unsigned long kval;
+ unsigned int *uvp;
+ int error;
+
+ set_fs(KERNEL_DS);
+ error = sys_ioctl(fd, cmd, (long)&kval);
+ set_fs(old_fs);
+
+ if(error == 0) {
+ uvp = (unsigned int *)A(arg);
+ if(put_user(kval, uvp))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+struct ppp_option_data32 {
+ __kernel_caddr_t32 ptr;
+ __u32 length;
+ int transmit;
+};
+#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
+
+static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ struct ppp_option_data32 data32;
+ struct ppp_option_data data;
+ int err;
+
+ switch (cmd) {
+ case PPPIOCSCOMPRESS32:
+ if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32)))
+ return -EFAULT;
+ data.ptr = kmalloc (data32.length, GFP_KERNEL);
+ if (!data.ptr)
+ return -ENOMEM;
+ if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
+ err = -EFAULT;
+ goto out;
+ }
+ data.length = data32.length;
+ data.transmit = data32.transmit;
+ break;
+ default:
+ printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, (unsigned int)arg);
+ return -EINVAL;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&data);
+ set_fs (old_fs);
+ if (err)
+ goto out;
+ switch (cmd) {
+ case PPPIOCSCOMPRESS32:
+ default:
+ break;
+ }
+out:
+ kfree(data.ptr);
+ return err;
+}
+
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file * filp;
@@ -527,6 +628,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSIFDSTADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
+ case SIOCGPPPSTATS:
+ case SIOCGPPPCSTATS:
+ case SIOCGPPPVER:
error = dev_ifsioc(fd, cmd, arg);
goto out;
@@ -557,6 +661,16 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = fbiogscursor(fd, cmd, arg);
goto out;
+ case HDIO_GET_KEEPSETTINGS:
+ case HDIO_GET_UNMASKINTR:
+ case HDIO_GET_DMA:
+ case HDIO_GET_32BIT:
+ case HDIO_GET_MULTCOUNT:
+ case HDIO_GET_NOWERR:
+ case HDIO_GET_NICE:
+ error = hdio_ioctl_trans(fd, cmd, arg);
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
@@ -619,6 +733,23 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case FIBMAP:
case FIGETBSZ:
+ /* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ * Some need translations, these do not.
+ */
+ case HDIO_GET_IDENTITY:
+ case HDIO_SET_DMA:
+ case HDIO_SET_KEEPSETTINGS:
+ case HDIO_SET_UNMASKINTR:
+ case HDIO_SET_NOWERR:
+ case HDIO_SET_32BIT:
+ case HDIO_SET_MULTCOUNT:
+ case HDIO_DRIVE_CMD:
+ case HDIO_SET_PIO_MODE:
+ case HDIO_SCAN_HWIF:
+ case HDIO_SET_NICE:
+ case BLKROSET:
+ case BLKROGET:
+
/* 0x02 -- Floppy ioctls */
case FDSETEMSGTRESH:
case FDFLUSH:
@@ -729,11 +860,40 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSARP:
case SIOCGARP:
case SIOCDARP:
+ case OLD_SIOCSARP:
+ case OLD_SIOCGARP:
+ case OLD_SIOCDARP:
+ case SIOCSRARP:
+ case SIOCGRARP:
+ case SIOCDRARP:
case SIOCADDDLCI:
case SIOCDELDLCI:
+
+ /* PPP stuff */
+ case PPPIOCGFLAGS:
+ case PPPIOCSFLAGS:
+ case PPPIOCGASYNCMAP:
+ case PPPIOCSASYNCMAP:
+ case PPPIOCGUNIT:
+ case PPPIOCGRASYNCMAP:
+ case PPPIOCSRASYNCMAP:
+ case PPPIOCGMRU:
+ case PPPIOCSMRU:
+ case PPPIOCSMAXCID:
+ case PPPIOCGXASYNCMAP:
+ case PPPIOCSXASYNCMAP:
+ case PPPIOCXFERUNIT:
+ case PPPIOCGNPMODE:
+ case PPPIOCSNPMODE:
+ case PPPIOCGDEBUG:
+ case PPPIOCSDEBUG:
+ case PPPIOCGIDLE:
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
- break;
+
+ case PPPIOCSCOMPRESS32:
+ error = ppp_ioctl (fd, cmd, (unsigned long)arg);
+ goto out;
default:
printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
index 7d1580b39..7ae12df11 100644
--- a/arch/sparc64/kernel/ioport.c
+++ b/arch/sparc64/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
+/* $Id: ioport.c,v 1.13 1997/08/18 01:20:22 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,7 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
u32 bus_type, int rdonly)
{
unsigned long vaddr, base_address;
- unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+ unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
unsigned long offset = (addr & (~PAGE_MASK));
if (virtual) {
@@ -64,7 +64,12 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
/* Tell Linux resource manager about the mapping */
request_region ((vaddr | offset), len, name);
} else {
- return __va(addr);
+ unsigned long vaddr = (unsigned long) __va(addr);
+
+ if(!check_region(vaddr, len))
+ request_region(vaddr, len, name);
+
+ return (void *) vaddr;
}
base_address = vaddr;
@@ -83,11 +88,11 @@ void sparc_free_io (void *virtual, int len)
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
+ release_region(vaddr, plen);
+
if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
return;
- release_region(vaddr, plen);
-
for (; plen != 0;) {
plen -= PAGE_SIZE;
unmapioaddr(vaddr + plen);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index f76c27c57..6f4c9dfdf 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
+/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -28,8 +28,18 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <asm/pbm.h>
+#endif
+
/* Internal flag, should not be visible elsewhere at all. */
-#define SA_SYSIO_MASKED 0x100
+#define SA_IMAP_MASKED 0x100
+
+#ifdef __SMP__
+void distribute_irqs(void);
+static int irqs_have_been_distributed = 0;
+#endif
/* UPA nodes send interrupt packet to UltraSparc with first data reg value
* low 5 bits holding the IRQ identifier being delivered. We must translate
@@ -37,10 +47,39 @@
* make things even more swift we store the complete mask here.
*/
-#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */
+#define NUM_HARD_IVECS 2048
+#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */
unsigned long ivector_to_mask[NUM_IVECS];
+struct ino_bucket {
+ struct ino_bucket *next;
+ unsigned int ino;
+ unsigned int *imap;
+ unsigned int *iclr;
+};
+
+#define INO_HASHSZ (NUM_HARD_IVECS >> 2)
+#define NUM_INO_STATIC 4
+static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
+static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
+static int static_ino_bucket_count = 0;
+
+static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
+{
+ struct ino_bucket *ret = ino_hash[hash];
+
+ for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
+ ;
+
+ return ret;
+}
+
+static inline struct ino_bucket *ino_lookup(unsigned int ino)
+{
+ return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
+}
+
/* This is based upon code in the 32-bit Sparc kernel written mostly by
* David Redman (djhr@tadpole.co.uk).
*/
@@ -73,15 +112,22 @@ int get_irq_list(char *buf)
}
len += sprintf(buf + len, "\n");
}
+#if 0
+#ifdef CONFIG_PCI
+ len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n",
+ psycho_root->psycho_regs->pci_istate,
+ psycho_root->psycho_regs->obio_istate);
+#endif
+#endif
return len;
}
-/* INO number to Sparc PIL level. */
-unsigned char ino_to_pil[] = {
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */
+/* SBUS SYSIO INO number to Sparc PIL level. */
+unsigned char sysio_ino_to_pil[] = {
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
3, /* Onboard SCSI */
5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */
@@ -112,7 +158,7 @@ unsigned char ino_to_pil[] = {
*/
#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
#define bogon ((unsigned long) -1)
-static unsigned long irq_offsets[] = {
+static unsigned long sysio_irq_offsets[] = {
/* SBUS Slot 0 --> 3, level 1 --> 7 */
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
@@ -134,29 +180,29 @@ offset(imap_pmgmt),
#undef bogon
-#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
-/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
- * Interrupt Mapping register pointer, or NULL if none exists.
+/* XXX Old compatability cruft, get rid of me when all drivers have been
+ * XXX converted to dcookie registry calls... -DaveM
*/
-static unsigned int *irq_to_imap(unsigned int irq)
+static unsigned int *sysio_irq_to_imap(unsigned int irq)
{
unsigned long offset;
struct sysio_regs *sregs;
if((irq == 14) ||
- (irq >= NUM_IRQ_ENTRIES) ||
- ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+ (irq >= NUM_SYSIO_OFFSETS) ||
+ ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
return NULL;
sregs = SBus_chain->iommu->sysio_regs;
offset += ((unsigned long) sregs);
- return ((unsigned int *)offset) + 1;
+ return ((unsigned int *)offset);
}
/* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer.
+ * Interrupt Clear register pointer, SYSIO specific version.
*/
-static unsigned int *imap_to_iclr(unsigned int *imap)
+static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
{
unsigned long diff;
@@ -166,32 +212,68 @@ static unsigned int *imap_to_iclr(unsigned int *imap)
#undef offset
-/* For non-SBUS IRQ's we do nothing, else we must enable them in the
- * appropriate SYSIO interrupt map registers.
+#ifdef CONFIG_PCI
+/* PCI PSYCHO INO number to Sparc PIL level. */
+unsigned char psycho_ino_to_pil[] = {
+ 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */
+ 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
+ 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */
+ 3, /* SCSI */
+ 5, /* Ethernet */
+ 8, /* Parallel Port */
+ 13, /* Audio Record */
+ 14, /* Audio Playback */
+ 15, /* PowerFail */
+ 12, /* Keyboard/Mouse/Serial */
+ 11, /* Floppy */
+ 2, /* Spare Hardware */
+ 12, /* Keyboard */
+ 4, /* Mouse */
+ 12, /* Serial */
+ 10, /* Timer 0 */
+ 11, /* Timer 1 */
+ 15, /* Uncorrectable ECC */
+ 15, /* Correctable ECC */
+ 15, /* PCI Bus A Error */
+ 15, /* PCI Bus B Error */
+ 1, /* Power Management */
+};
+
+/* INO number to IMAP register offset for PSYCHO external IRQ's.
*/
-void enable_irq(unsigned int irq)
+#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
+
+#define psycho_imap_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
+
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+
+#endif
+
+/* Now these are always passed a true fully specified sun4u INO. */
+void enable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket;
unsigned long tid;
unsigned int *imap;
- /* If this is for the tick interrupt, just ignore, note
- * that this is the one and only locally generated interrupt
- * source, all others come from external sources (essentially
- * any UPA device which is an interruptor). (actually, on
- * second thought Ultra can generate local interrupts for
- * async memory errors and we may setup handlers for those
- * at some point as well)
- *
- * XXX See commentary below in request_irq() this assumption
- * XXX is broken and needs to be fixed.
- */
- if(irq == 14)
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(ino))
+ ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
+#endif
+ bucket = ino_lookup(ino);
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* We send it to our UPA MID, for SMP this will be different. */
__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -202,28 +284,27 @@ void enable_irq(unsigned int irq)
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* SYSIO_IMAP_INR field can be set by the programmer here.
- * (XXX we will have to handle those for FFB etc. XXX)
+ *
+ * Things like FFB can now be handled via the dcookie mechanism.
*/
*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
- return;
-
-do_the_stb_watoosi:
- printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
}
-void disable_irq(unsigned int irq)
+/* This now gets passed true ino's as well. */
+void disable_irq(unsigned int ino)
{
+ struct ino_bucket *bucket;
unsigned int *imap;
- /* XXX Grrr, I know this is broken... */
- if(irq == 14)
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(ino))
+ ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
+#endif
+ bucket = ino_lookup(ino);
+ if(!bucket)
return;
- /* Check for bogons. */
- imap = irq_to_imap(irq);
- if(imap == NULL)
- goto do_the_stb_watoosi;
+ imap = bucket->imap;
/* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call
@@ -231,34 +312,254 @@ void disable_irq(unsigned int irq)
* SCSI adapter driver code. Thus we'd lose interrupts.
*/
*imap &= ~(SYSIO_IMAP_VALID);
- return;
+}
+
+static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
+ unsigned int **imap, unsigned int **iclr,
+ void *busp, unsigned long flags,
+ unsigned int irq)
+{
+ if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
+ return;
+
+ if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
+ printk("get_irq_translations: Partial specification, this is bad.\n");
+ printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
+ *cpu_irq, *imap, *iclr, busp);
+ panic("Bad IRQ translations...");
+ }
+
+ if(SA_BUS(flags) == SA_SBUS) {
+ struct linux_sbus *sbusp = busp;
+ struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
+ unsigned long offset;
-do_the_stb_watoosi:
- printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
- panic("Trying to enable bogon IRQ");
+ *cpu_irq = sysio_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
+ panic("Bad SYSIO IRQ translations...");
+ }
+ offset = sysio_irq_offsets[irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("BAD SYSIO IRQ offset...");
+ }
+ offset += ((unsigned long)sregs);
+ *imap = ((unsigned int *)offset);
+
+ /* SYSIO inconsistancy. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if(irq >= 0x20) {
+ *iclr = sysio_imap_to_iclr(*imap);
+ } else {
+ unsigned long iclraddr;
+ int sbus_slot = (irq & 0x18)>>3;
+ int sbus_level = irq & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ *iclr = &sregs->iclr_slot0;
+ break;
+ case 1:
+ *iclr = &sregs->iclr_slot1;
+ break;
+ case 2:
+ *iclr = &sregs->iclr_slot2;
+ break;
+ case 3:
+ *iclr = &sregs->iclr_slot3;
+ break;
+ };
+
+ iclraddr = (unsigned long) *iclr;
+ iclraddr += ((sbus_level - 1) * 8);
+ *iclr = (unsigned int *) iclraddr;
+
+#if 0 /* DEBUGGING */
+ printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
+ sbus_slot, sbus_level, *iclr);
+#endif
+
+ /* Also, make sure this is accounted for in ivindex
+ * computations done by the caller.
+ */
+ *ivindex_fixup = sbus_level;
+ }
+ return;
+ }
+#ifdef CONFIG_PCI
+ if(SA_BUS(flags) == SA_PCI) {
+ struct pci_bus *pbusp = busp;
+ struct linux_pbm_info *pbm = pbusp->sysdata;
+ struct psycho_regs *pregs = pbm->parent->psycho_regs;
+ unsigned long offset;
+
+ *cpu_irq = psycho_ino_to_pil[irq & 0x3f];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ translations...");
+ }
+ offset = psycho_imap_offset(irq);
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad PSYCHO IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = ((unsigned int *)offset) + 1;
+ *iclr = (unsigned int *)
+ (((unsigned long)pregs) + psycho_imap_offset(irq));
+ return;
+ }
+#endif
+#if 0 /* XXX More to do before we can use this. -DaveM */
+ if(SA_BUS(flags) == SA_FHC) {
+ struct fhc_bus *fbusp = busp;
+ struct fhc_regs *fregs = fbusp->regs;
+ unsigned long offset;
+
+ *cpu_irq = fhc_ino_to_pil[irq];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
+ panic("Bad FHC IRQ translations...");
+ }
+ offset = fhc_irq_offset[*cpu_irq];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
+ irq, *cpu_irq);
+ panic("Bad FHC IRQ offset...");
+ }
+ offset += ((unsigned long)pregs);
+ *imap = (((unsigned int *)offset)+1);
+ *iclr = fhc_imap_to_iclr(*imap);
+ return;
+ }
+#endif
+ printk("get_irq_translations: IRQ register for unknown bus type.\n");
+ printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
+ SA_BUS(flags), irq);
+ panic("Bad IRQ bus type...");
+}
+
+#ifdef CONFIG_PCI
+static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup,
+ unsigned int **imap, unsigned int **iclr,
+ unsigned int irq)
+{
+ struct linux_psycho *psycho = psycho_root;
+ struct psycho_regs *pregs = psycho->psycho_regs;
+ unsigned long addr, imoff;
+
+ addr = (unsigned long) &pregs->imap_a_slot0;
+ imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT;
+ addr = addr + imoff;
+
+ *imap = ((unsigned int *)addr) + 1;
+
+ addr = (unsigned long) pregs;
+ addr += psycho_iclr_offset(irq & (PCI_IRQ_INO));
+ *iclr = ((unsigned int *)addr) + 1;
+
+ *cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)];
+ if(*cpu_irq == 0) {
+ printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ frobnication...");
+ }
+
+ /* IVINDEX fixup only needed for PCI slot irq lines. */
+ if(!(irq & 0x20))
+ *ivindex_fixup = irq & 0x03;
+}
+#endif
+
+/* Once added, they are never removed. */
+static struct ino_bucket *add_ino_hash(unsigned int ivindex,
+ unsigned int *imap, unsigned int *iclr,
+ unsigned long flags)
+{
+ struct ino_bucket *new = NULL, **hashp;
+ unsigned int hash = (ivindex & (INO_HASHSZ - 1));
+
+ new = __ino_lookup(hash, ivindex);
+ if(new)
+ return new;
+ if(flags & SA_STATIC_ALLOC) {
+ if(static_ino_bucket_count < NUM_INO_STATIC)
+ new = &static_ino_buckets[static_ino_bucket_count++];
+ else
+ printk("Request for ino bucket SA_STATIC_ALLOC failed "
+ "using kmalloc\n");
+ }
+ if(new == NULL)
+ new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
+ if(new) {
+ hashp = &ino_hash[hash];
+ new->imap = imap;
+ new->iclr = iclr;
+ new->ino = ivindex;
+ new->next = *hashp;
+ *hashp = new;
+ }
+ return new;
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name, void *dev_cookie)
+ unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action, *tmp = NULL;
+ struct devid_cookie *dcookie = NULL;
+ struct ino_bucket *bucket = NULL;
unsigned long flags;
- unsigned int cpu_irq, *imap, *iclr;
+ unsigned int *imap, *iclr;
+ void *bus_id = NULL;
+ int ivindex, ivindex_fixup, cpu_irq = -1;
- /* XXX This really is not the way to do it, the "right way"
- * XXX is to have drivers set SA_SBUS or something like that
- * XXX in irqflags and we base our decision here on whether
- * XXX that flag bit is set or not.
- */
- if(irq == 14)
- cpu_irq = irq;
- else
- cpu_irq = ino_to_pil[irq];
-
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = iclr = NULL;
+
+ ivindex_fixup = 0;
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(irq)) {
+ pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
+ } else
+#endif
+ if(irqflags & SA_DCOOKIE) {
+ if(!dev_id) {
+ printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+ panic("Bogus irq registry.");
+ }
+ dcookie = dev_id;
+ dev_id = dcookie->real_dev_id;
+ cpu_irq = dcookie->pil;
+ imap = dcookie->imap;
+ iclr = dcookie->iclr;
+ bus_id = dcookie->bus_cookie;
+ get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+ &iclr, bus_id, irqflags, irq);
+ } else {
+ /* XXX NOTE: This code is maintained for compatability until I can
+ * XXX verify that all drivers sparc64 will use are updated
+ * XXX to use the new IRQ registry dcookie interface. -DaveM
+ */
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = sysio_ino_to_pil[irq];
+ imap = sysio_irq_to_imap(irq);
+ if(!imap) {
+ printk("request_irq: BAD, null imap for old style "
+ "irq registry IRQ[%x].\n", irq);
+ panic("Bad IRQ registery...");
+ }
+ iclr = sysio_imap_to_iclr(imap);
+ }
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ ivindex += ivindex_fixup;
action = *(cpu_irq + irq_action);
if(action) {
@@ -297,52 +598,67 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return -ENOMEM;
}
- if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+ if(!bucket) {
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
+ }
- ivector_to_mask[ivindex] = (1<<cpu_irq);
- iclr = imap_to_iclr(imap);
- action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
- } else {
- action->mask = 0;
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+ if(dcookie) {
+ dcookie->ret_ino = ivindex;
+ dcookie->ret_pil = cpu_irq;
}
+ action->mask = (unsigned long) bucket;
action->handler = handler;
- action->flags = irqflags;
+ action->flags = irqflags | SA_IMAP_MASKED;
action->name = name;
action->next = NULL;
- action->dev_id = dev_cookie;
+ action->dev_id = dev_id;
if(tmp)
tmp->next = action;
else
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ enable_irq(ivindex);
restore_flags(flags);
+#ifdef __SMP__
+ if(irqs_have_been_distributed)
+ distribute_irqs();
+#endif
return 0;
}
-void free_irq(unsigned int irq, void *dev_cookie)
+void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action;
struct irqaction *tmp = NULL;
unsigned long flags;
unsigned int cpu_irq;
+ int ivindex = -1;
- if(irq == 14)
+ if(irq == 14) {
cpu_irq = irq;
- else
- cpu_irq = ino_to_pil[irq];
+ } else {
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(irq))
+ cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO];
+ else
+#endif
+ cpu_irq = sysio_ino_to_pil[irq];
+ }
action = *(cpu_irq + irq_action);
if(!action->handler) {
printk("Freeing free IRQ %d\n", irq);
return;
}
- if(dev_cookie) {
+ if(dev_id) {
for( ; action; action = action->next) {
- if(action->dev_id == dev_cookie)
+ if(action->dev_id == dev_id)
break;
tmp = action;
}
@@ -351,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_cookie)
return;
}
} else if(action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+ printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
return;
}
@@ -367,29 +683,37 @@ void free_irq(unsigned int irq, void *dev_cookie)
else
*(cpu_irq + irq_action) = action->next;
- if(action->flags & SA_SYSIO_MASKED) {
- unsigned int *imap = irq_to_imap(irq);
- if(imap != NULL)
- ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+ if(action->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+ unsigned int *imap = bucket->imap;
+
+ if(imap != NULL) {
+ ivindex = bucket->ino;
+ ivector_to_mask[ivindex] = 0;
+ }
else
printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
}
kfree(action);
- if(!*(cpu_irq + irq_action))
- disable_irq(irq);
+ if(ivindex != -1)
+ disable_irq(ivindex);
restore_flags(flags);
}
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
-unsigned int local_irq_count[NR_CPUS];
+/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
+ * structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned int local_irq_count;
+#endif
#ifndef __SMP__
int __sparc64_bh_counter = 0;
-#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
-#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
+#define irq_enter(cpu, irq) (local_irq_count++)
+#define irq_exit(cpu, irq) (local_irq_count--)
#else
@@ -407,18 +731,31 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
-static inline void wait_on_irq(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 local_count = local_irq_count[cpu];
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count;
while(local_count != atomic_read(&global_irq_count)) {
atomic_sub(local_count, &global_irq_count);
spin_unlock(&global_irq_lock);
for(;;) {
+ STUCK;
+ membar("#StoreLoad | #LoadLoad");
if (atomic_read(&global_irq_count))
continue;
- if (*((unsigned char *)&global_irq_lock))
+ if (*((volatile unsigned char *)&global_irq_lock))
continue;
+ membar("#LoadLoad | #LoadStore");
if (spin_trylock(&global_irq_lock))
break;
}
@@ -426,25 +763,41 @@ static inline void wait_on_irq(int cpu)
}
}
-static inline void get_irqlock(int cpu)
+#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)) {
+ membar("#StoreLoad | #LoadLoad");
if ((unsigned char) cpu == global_irq_holder)
return;
do {
- barrier();
+ do {
+ STUCK;
+ membar("#LoadLoad");
+ } while(*((volatile unsigned char *)&global_irq_lock));
} while (!spin_trylock(&global_irq_lock));
}
- wait_on_irq(cpu);
+ wait_on_irq(cpu, where);
global_irq_holder = cpu;
+ previous_irqholder = where;
}
void __global_cli(void)
{
int cpu = smp_processor_id();
+ unsigned long where;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
__cli();
- get_irqlock(cpu);
+ get_irqlock(cpu, where);
}
void __global_sti(void)
@@ -453,11 +806,6 @@ void __global_sti(void)
__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) {
@@ -472,15 +820,24 @@ void __global_restore_flags(unsigned long flags)
}
}
+#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;}
+
void irq_enter(int cpu, int irq)
{
+ int stuck = INIT_STUCK;
+
hardirq_enter(cpu);
- barrier();
- while (*((unsigned char *)&global_irq_lock)) {
+ while (*((volatile unsigned char *)&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder)
printk("irq_enter: Frosted Lucky Charms, "
"they're magically delicious!\n");
- barrier();
+ STUCK;
+ membar("#LoadLoad");
}
}
@@ -492,8 +849,7 @@ void irq_exit(int cpu, int irq)
void synchronize_irq(void)
{
- int cpu = smp_processor_id();
- int local_count = local_irq_count[cpu];
+ int local_count = local_irq_count;
unsigned long flags;
if (local_count != atomic_read(&global_irq_count)) {
@@ -506,9 +862,13 @@ void synchronize_irq(void)
void report_spurious_ivec(struct pt_regs *regs)
{
- printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
- regs->tpc);
- return;
+ extern unsigned long ivec_spurious_cookie;
+ static int times = 0;
+
+ printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
+ ivec_spurious_cookie, regs->tpc);
+ if(times++ > 1)
+ prom_halt();
}
void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
@@ -547,13 +907,28 @@ void handler_irq(int irq, struct pt_regs *regs)
irq_enter(cpu, irq);
action = *(irq + irq_action);
kstat.interrupts[irq]++;
- do {
- if(!action || !action->handler)
- unexpected_irq(irq, 0, regs);
- action->handler(irq, action->dev_id, regs);
- if(action->flags & SA_SYSIO_MASKED)
- *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
- } while((action = action->next) != NULL);
+ if(!action) {
+ unexpected_irq(irq, 0, regs);
+ } else {
+ do {
+ struct ino_bucket *bucket = NULL;
+ unsigned int ino = 0;
+
+ if(action->flags & SA_IMAP_MASKED) {
+ bucket = (struct ino_bucket *)action->mask;
+
+ ino = bucket->ino;
+ if(!(ivector_to_mask[ino] & 0x80000000))
+ continue;
+ }
+
+ action->handler(irq, action->dev_id, regs);
+ if(bucket) {
+ ivector_to_mask[ino] &= ~(0x80000000);
+ *(bucket->iclr) = SYSIO_ICLR_IDLE;
+ }
+ } while((action = action->next) != NULL);
+ }
irq_exit(cpu, irq);
}
@@ -567,7 +942,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
irq_enter(cpu, irq);
floppy_interrupt(irq, dev_cookie, regs);
- if(action->flags & SA_SYSIO_MASKED)
+ if(action->flags & SA_IMAP_MASKED)
*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
irq_exit(cpu, irq);
}
@@ -595,7 +970,7 @@ static void install_fast_irq(unsigned int cpu_irq,
insns[0] = SPARC_BRANCH(((unsigned long) handler),
((unsigned long)&insns[0]));
insns[1] = SPARC_NOP;
- __asm__ __volatile__("flush %0" : : "r" (ttent));
+ __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
}
int request_fast_irq(unsigned int irq,
@@ -605,6 +980,7 @@ int request_fast_irq(unsigned int irq,
struct irqaction *action;
unsigned long flags;
unsigned int cpu_irq, *imap, *iclr;
+ int ivindex = -1;
/* XXX This really is not the way to do it, the "right way"
* XXX is to have drivers set SA_SBUS or something like that
@@ -616,11 +992,11 @@ int request_fast_irq(unsigned int irq,
*/
if(irq == 14)
return -EINVAL;
- cpu_irq = ino_to_pil[irq];
+ cpu_irq = sysio_ino_to_pil[irq];
if(!handler)
return -EINVAL;
- imap = irq_to_imap(irq);
+ imap = sysio_irq_to_imap(irq);
action = *(cpu_irq + irq_action);
if(action) {
if(action->flags & SA_SHIRQ)
@@ -648,12 +1024,12 @@ int request_fast_irq(unsigned int irq,
install_fast_irq(cpu_irq, handler);
if(imap) {
- int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
ivector_to_mask[ivindex] = (1 << cpu_irq);
- iclr = imap_to_iclr(imap);
+ iclr = sysio_imap_to_iclr(imap);
action->mask = (unsigned long) iclr;
- irqflags |= SA_SYSIO_MASKED;
+ irqflags |= SA_IMAP_MASKED;
+ add_ino_hash(ivindex, imap, iclr, irqflags);
} else
action->mask = 0;
@@ -665,7 +1041,9 @@ int request_fast_irq(unsigned int irq,
*(cpu_irq + irq_action) = action;
- enable_irq(irq);
+ if(ivindex != -1)
+ enable_irq(ivindex);
+
restore_flags(flags);
return 0;
}
@@ -675,31 +1053,27 @@ int request_fast_irq(unsigned int irq,
*/
unsigned long probe_irq_on(void)
{
- return 0;
+ return 0;
}
int probe_irq_off(unsigned long mask)
{
- return 0;
+ return 0;
}
struct sun5_timer *linux_timers = NULL;
-/* This is called from sbus_init() to get the jiffies timer going.
- * We need to call this after there exists a valid SBus_chain so
- * that the IMAP/ICLR registers can be accessed.
- *
- * XXX That is because the whole startup sequence is broken. I will
- * XXX fix it all up very soon. -DaveM
- */
+/* This is gets the master level10 timer going. */
void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
struct linux_prom64_registers pregs[3];
+ struct devid_cookie dcookie;
+ unsigned int *imap, *iclr;
u32 pirqs[2];
int node, err;
node = prom_finddevice("/counter-timer");
- if(node == 0) {
+ if(node == 0 || node == -1) {
prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
prom_halt();
}
@@ -715,13 +1089,22 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
prom_halt();
}
linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
+ iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
+ imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
/* Shut it up first. */
linux_timers->limit0 = 0;
/* Register IRQ handler. */
- err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
- cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+ dcookie.real_dev_id = NULL;
+ dcookie.imap = imap;
+ dcookie.iclr = iclr;
+ dcookie.pil = 10;
+ dcookie.bus_cookie = NULL;
+
+ err = request_irq(pirqs[0], cfunc,
+ (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", &dcookie);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
@@ -825,6 +1208,52 @@ void enable_prom_timer(void)
prom_timers->count0 = 0;
}
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+ unsigned long flags;
+ int cpu, level;
+
+ printk("SMP: redistributing interrupts...\n");
+ save_and_cli(flags);
+ cpu = 0;
+ for(level = 0; level < NR_IRQS; level++) {
+ struct irqaction *p = irq_action[level];
+
+ while(p) {
+ if(p->flags & SA_IMAP_MASKED) {
+ struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+ unsigned int *imap = bucket->imap;
+ unsigned int val;
+ unsigned long tid = linux_cpus[cpu].mid << 9;
+
+ val = *imap;
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+ printk("SMP: Redirecting IGN[%x] INO[%x] "
+ "to cpu %d [%s]\n",
+ (val & SYSIO_IMAP_IGN) >> 6,
+ (val & SYSIO_IMAP_INO), cpu,
+ p->name);
+
+ cpu += 1;
+ while(!(cpu_present_map & (1UL << cpu))) {
+ cpu += 1;
+ if(cpu >= smp_num_cpus)
+ cpu = 0;
+ }
+ }
+ p = p->next;
+ }
+ }
+ restore_flags(flags);
+ irqs_have_been_distributed = 1;
+}
+#endif
+
__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index afd5af8d0..35d4d606d 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
+/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,18 +27,21 @@
#include <linux/a.out.h>
#include <linux/config.h>
#include <linux/reboot.h>
+#include <linux/delay.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/pstate.h>
#include <asm/elf.h>
#include <asm/fpumacro.h>
+#define PGTCACHE_HIGH_WATER 50
+#define PGTCACHE_LOW_WATER 25
+
#ifndef __SMP__
/*
@@ -53,6 +56,16 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
run_task_queue(&tq_scheduler);
schedule();
}
@@ -68,13 +81,26 @@ asmlinkage int cpu_idle(void)
{
current->priority = -100;
while(1) {
+ if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+ do {
+ if(pgd_quicklist)
+ free_page((unsigned long) get_pgd_fast());
+ if(pmd_quicklist)
+ free_page((unsigned long) get_pmd_fast());
+ if(pte_quicklist)
+ free_page((unsigned long) get_pte_fast());
+ } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+ }
if(tq_scheduler) {
lock_kernel();
run_task_queue(&tq_scheduler);
unlock_kernel();
}
+ barrier();
current->counter = -100;
- schedule();
+ if(resched_needed())
+ schedule();
+ barrier();
}
}
@@ -251,8 +277,20 @@ void show_stackframe32(struct sparc_stackf32 *sf)
} while ((size -= sizeof(unsigned)));
}
-void show_regs(struct pt_regs * regs)
+#ifdef __SMP__
+static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+void __show_regs(struct pt_regs * regs)
{
+#ifdef __SMP__
+ unsigned long flags;
+
+ spin_lock_irqsave(&regdump_lock, flags);
+ printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+ smp_processor_id(), local_irq_count,
+ atomic_read(&global_irq_count));
+#endif
printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
regs->tpc, regs->tnpc, regs->y);
printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
@@ -268,6 +306,21 @@ void show_regs(struct pt_regs * regs)
regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
regs->u_regs[15]);
show_regwindow(regs);
+#ifdef __SMP__
+ spin_unlock_irqrestore(&regdump_lock, flags);
+#endif
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ __show_regs(regs);
+#ifdef __SMP__
+ {
+ extern void smp_report_regs(void);
+
+ smp_report_regs();
+ }
+#endif
}
void show_regs32(struct pt_regs32 *regs)
@@ -332,17 +385,22 @@ void flush_thread(void)
/* No new signal delivery by default. */
current->tss.new_signal = 0;
- current->flags &= ~PF_USEDFPU;
+ current->tss.flags &= ~(SPARC_FLAG_USEDFPU | SPARC_FLAG_USEDFPUL |
+ SPARC_FLAG_USEDFPUU);
/* Now, this task is no longer a kernel thread. */
current->tss.current_ds = USER_DS;
if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ extern spinlock_t scheduler_lock;
+
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
/* exec_mmap() set context to NO_CONTEXT, here is
* where we grab a new one.
*/
+ spin_lock(&scheduler_lock);
get_mmu_context(current);
+ spin_unlock(&scheduler_lock);
}
current->tss.ctx = current->mm->context & 0x1fff;
spitfire_set_secondary_context (current->tss.ctx);
@@ -437,10 +495,14 @@ void fault_in_user_windows(struct pt_regs *regs)
struct reg_window *rwin = &tp->reg_window[window];
if(copy_to_user((char *)sp, rwin, winsize))
- do_exit(SIGILL);
+ goto barf;
} while(window--);
}
current->tss.w_saved = 0;
+ return;
+barf:
+ lock_kernel();
+ do_exit(SIGILL);
}
/* Copy a Sparc thread. The fork() return value conventions
@@ -483,7 +545,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
- p->tss.cwp = regs->u_regs[UREG_G0];
+ p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
if(regs->tstate & TSTATE_PRIV) {
p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
p->tss.flags |= SPARC_FLAG_KTHREAD;
@@ -581,6 +643,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
regs->fprs = 0;
+ regs->tstate &= ~TSTATE_PEF;
}
out:
unlock_kernel();
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
new file mode 100644
index 000000000..8aa1c342b
--- /dev/null
+++ b/arch/sparc64/kernel/psycho.c
@@ -0,0 +1,1417 @@
+/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $
+ * psycho.c: Ultra/AX U2P PCI controller support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+
+#else
+
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#include <asm/uaccess.h>
+
+struct linux_psycho *psycho_root = NULL;
+
+/* This is used to make the scan_bus in the generic PCI code be
+ * a nop, as we need to control the actual bus probing sequence.
+ * After that we leave it on of course.
+ */
+static int pci_probe_enable = 0;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+ return ((addr + (sizeof(unsigned long) - 1)) &
+ ~(sizeof(unsigned long) - 1));
+}
+
+static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
+ unsigned long memory_start)
+{
+ unsigned long tsbbase = PAGE_ALIGN(memory_start);
+ unsigned long control, i;
+ unsigned long *iopte;
+
+ memory_start = (tsbbase + ((32 * 1024) * 8));
+ iopte = (unsigned long *)tsbbase;
+
+ for(i = 0; i < (65536 / 2); i++) {
+ *iopte = (IOPTE_VALID | IOPTE_64K |
+ IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= (i << 16);
+ iopte++;
+ }
+
+ psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
+
+ control = psycho->psycho_regs->iommu_control;
+ control &= ~(IOMMU_CTRL_TSBSZ);
+ control |= (IOMMU_TSBSZ_32K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ psycho->psycho_regs->iommu_control = control;
+
+ return memory_start;
+}
+
+extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+
+unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_prom64_registers pr_regs[3];
+ char namebuf[128];
+ u32 portid;
+ int node;
+
+ printk("PSYCHO: Probing for controllers.\n");
+
+ memory_start = long_align(memory_start);
+ node = prom_getchild(prom_root_node);
+ while((node = prom_searchsiblings(node, "pci")) != 0) {
+ struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
+ struct linux_psycho *search;
+ struct linux_pbm_info *pbm = NULL;
+ u32 busrange[2];
+ int err, is_pbm_a;
+
+ portid = prom_getintdefault(node, "upa-portid", 0xff);
+ for(search = psycho_root; search; search = search->next) {
+ if(search->upa_portid == portid) {
+ psycho = search;
+
+ /* This represents _this_ instance, so it's
+ * which ever one does _not_ have the prom node
+ * info filled in yet.
+ */
+ is_pbm_a = (psycho->pbm_A.prom_node == 0);
+ goto other_pbm;
+ }
+ }
+
+ memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+ memset(psycho, 0, sizeof(*psycho));
+
+ psycho->next = psycho_root;
+ psycho_root = psycho;
+
+ psycho->upa_portid = portid;
+
+ /* Map in PSYCHO register set and report the presence of this PSYCHO. */
+ err = prom_getproperty(node, "reg",
+ (char *)&pr_regs[0], sizeof(pr_regs));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get U2P registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ /* Third REG in property is base of entire PSYCHO register space. */
+ psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+ NULL, sizeof(struct psycho_regs),
+ "PSYCHO Registers",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->psycho_regs == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PSYCHO "
+ "main registers.\n");
+ prom_halt();
+ }
+
+ printk("PSYCHO: Found controller, main regs at %p\n",
+ psycho->psycho_regs);
+#if 0
+ printk("PSYCHO: Interrupt retry [%016lx]\n",
+ psycho->psycho_regs->irq_retry);
+#endif
+ psycho->psycho_regs->irq_retry = 0xff;
+
+ /* Now map in PCI config space for entire PSYCHO. */
+ psycho->pci_config_space =
+ sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+ NULL, 0x01000000,
+ "PCI Config Space",
+ (pr_regs[2].phys_addr >> 32), 0);
+ if(psycho->pci_config_space == NULL) {
+ prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
+ prom_halt();
+ }
+
+ /* Report some more info. */
+ printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+
+ memory_start = psycho_iommu_init(psycho, memory_start);
+
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+ /* Enable arbitration for all PCI slots. */
+ psycho->psycho_regs->pci_a_control |= 0x3f;
+ psycho->psycho_regs->pci_b_control |= 0x3f;
+
+ other_pbm:
+ if(is_pbm_a)
+ pbm = &psycho->pbm_A;
+ else
+ pbm = &psycho->pbm_B;
+
+ pbm->parent = psycho;
+ pbm->IO_assignments = NULL;
+ pbm->MEM_assignments = NULL;
+ pbm->prom_node = node;
+
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(pbm->prom_name, namebuf);
+
+ /* Now the ranges. */
+ prom_pbm_ranges_init(node, pbm);
+
+ /* Finally grab the pci bus root array for this pbm after
+ * having found the bus range existing under it.
+ */
+ err = prom_getproperty(node, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
+ prom_halt();
+ }
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+ memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+ node = prom_getsibling(node);
+ if(!node)
+ break;
+ }
+
+ /* Last minute sanity check. */
+ if(psycho_root == NULL && SBus_chain == NULL) {
+ prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
+ prom_halt();
+ }
+
+ return memory_start;
+}
+
+int pcibios_present(void)
+{
+ return psycho_root != NULL;
+}
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
+ unsigned long start,
+ int io)
+{
+ struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
+
+ while(vp) {
+ if(vp->end > start)
+ break;
+ vp = vp->next;
+ }
+ return vp;
+}
+
+static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io)
+{
+ struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
+
+ if(!vp) {
+ new->next = NULL;
+ if(io)
+ pbm->IO_assignments = new;
+ else
+ pbm->MEM_assignments = new;
+ } else {
+ struct pci_vma *prev = NULL;
+
+ while(vp && (vp->end < new->end)) {
+ prev = vp;
+ vp = vp->next;
+ }
+ new->next = vp;
+ if(!prev) {
+ if(io)
+ pbm->IO_assignments = new;
+ else
+ pbm->MEM_assignments = new;
+ } else {
+ prev->next = new;
+ }
+
+ /* Check for programming errors. */
+ if(vp &&
+ ((vp->start >= new->start && vp->start < new->end) ||
+ ((vp->end - 1) >= new->start && (vp->end - 1) < new->end))) {
+ prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
+ io ? "IO" : "MEM");
+ prom_printf("pci_add_vma: vp[%016lx:%016lx] "
+ "new[%016lx:%016lx]\n",
+ vp->start, vp->end,
+ new->start, new->end);
+ }
+ }
+}
+
+static unsigned long *pci_alloc_arena = NULL;
+
+static inline void pci_init_alloc_init(unsigned long *mstart)
+{
+ pci_alloc_arena = mstart;
+}
+
+static inline void pci_init_alloc_fini(void)
+{
+ pci_alloc_arena = NULL;
+}
+
+static void *pci_init_alloc(int size)
+{
+ unsigned long start = long_align(*pci_alloc_arena);
+ void *mp = (void *)start;
+
+ if(!pci_alloc_arena) {
+ prom_printf("pci_init_alloc: pci_vma arena not init'd\n");
+ prom_halt();
+ }
+ start += size;
+ *pci_alloc_arena = start;
+ return mp;
+}
+
+static inline struct pci_vma *pci_vma_alloc(void)
+{
+ return pci_init_alloc(sizeof(struct pci_vma));
+}
+
+static inline struct pcidev_cookie *pci_devcookie_alloc(void)
+{
+ return pci_init_alloc(sizeof(struct pcidev_cookie));
+}
+
+static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* PSYCHO PBM's include child PCI bridges in bus-range property,
+ * but we don't scan each of those ourselves, Linux generic PCI
+ * probing code will find child bridges and link them into this
+ * pbm's root PCI device hierarchy.
+ */
+ pbus->number = pbm->pci_first_busno;
+ pbus->sysdata = pbm;
+ pbus->subordinate = pci_scan_bus(pbus, mstart);
+}
+
+static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int node)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ int err;
+
+ while(node) {
+ int child;
+
+ child = prom_getchild(node);
+ if(child != 0 && child != -1) {
+ int res;
+
+ res = pdev_to_pnode_sibtraverse(pbm, pdev, child);
+ if(res != 0 && res != -1)
+ return res;
+ }
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err != 0 && err != -1) {
+ u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
+
+ if(devfn == pdev->devfn)
+ return node; /* Match */
+ }
+
+ node = prom_getsibling(node);
+ }
+ return 0;
+}
+
+static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
+{
+ struct pcidev_cookie *pcp;
+ int node = prom_getchild(pbm->prom_node);
+
+ node = pdev_to_pnode_sibtraverse(pbm, pdev, node);
+ if(node == 0)
+ node = -1;
+ pcp = pci_devcookie_alloc();
+ pcp->pbm = pbm;
+ pcp->prom_node = node;
+ pdev->sysdata = pcp;
+}
+
+static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
+ struct pci_dev *pdev;
+
+ for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
+ pbtmp->sysdata = pbm;
+
+ for( ; pbus; pbus = pbus->children)
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_cookie_fillin(pbm, pdev);
+}
+
+/* #define RECORD_ASSIGNMENTS_DEBUG */
+
+/* Walk PROM device tree under PBM, looking for 'assigned-address'
+ * properties, and recording them in pci_vma's linked in via
+ * PBM->assignments.
+ */
+static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
+{
+ struct linux_prom_ebus_ranges erng[PROMREG_MAX];
+ int err, iter;
+
+ err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng));
+ if(err == 0 || err == -1) {
+ prom_printf("EBUS: fatal error, no range property.\n");
+ prom_halt();
+ }
+ err = (err / sizeof(struct linux_prom_ebus_ranges));
+ for(iter = 0; iter < err; iter++) {
+ struct linux_prom_ebus_ranges *ep = &erng[iter];
+ struct linux_prom_pci_registers *ap = &aregs[iter];
+
+ ap->phys_hi = ep->parent_phys_hi;
+ ap->phys_mid = ep->parent_phys_mid;
+ ap->phys_lo = ep->parent_phys_lo;
+ }
+ return err;
+}
+
+static void assignment_process(struct linux_pbm_info *pbm, int node)
+{
+ struct linux_prom_pci_registers aregs[PROMREG_MAX];
+ char pname[256];
+ int err, iter, numa;
+
+ err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
+ if(strncmp(pname, "ebus", 4) == 0) {
+ numa = gimme_ebus_assignments(node, &aregs[0]);
+ } else {
+ err = prom_getproperty(node, "assigned-addresses",
+ (char *)&aregs[0], sizeof(aregs));
+
+ /* No assignments, nothing to do. */
+ if(err == 0 || err == -1)
+ return;
+
+ numa = (err / sizeof(struct linux_prom_pci_ranges));
+ }
+
+ for(iter = 0; iter < numa; iter++) {
+ struct linux_prom_pci_registers *ap = &aregs[iter];
+ struct pci_vma *vp;
+ int space, breg, io;
+
+ space = (ap->phys_hi >> 24) & 3;
+ if(space != 1 && space != 2)
+ continue;
+ io = (space == 1);
+
+ breg = (ap->phys_hi & 0xff);
+ if(breg == PCI_ROM_ADDRESS)
+ continue;
+
+ vp = pci_vma_alloc();
+
+ /* XXX Means we don't support > 32-bit range of
+ * XXX PCI MEM space, PSYCHO/PBM does not support it
+ * XXX either due to it's layout so...
+ */
+ vp->start = ap->phys_lo;
+ vp->end = vp->start + ap->size_lo;
+ vp->base_reg = breg;
+
+ /* Sanity */
+ if(io && (vp->end & ~(0xffff))) {
+ prom_printf("assignment_process: Out of range PCI I/O "
+ "[%08lx:%08lx]\n", vp->start, vp->end);
+ prom_halt();
+ }
+
+ pci_add_vma(pbm, vp, io);
+ }
+}
+
+static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
+{
+ while(node) {
+ int child = prom_getchild(node);
+ if(child)
+ assignment_walk_siblings(pbm, child);
+
+ assignment_process(pbm, node);
+
+ node = prom_getsibling(node);
+ }
+}
+
+static void record_assignments(struct linux_pbm_info *pbm)
+{
+ assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
+}
+
+/* #define FIXUP_REGS_DEBUG */
+
+static void fixup_regs(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ struct linux_prom_pci_registers *assigned,
+ int numaa)
+{
+ int preg, rng;
+ int IO_seen = 0;
+ int MEM_seen = 0;
+
+ for(preg = 0; preg < nregs; preg++) {
+ struct linux_prom_pci_registers *ap = NULL;
+ int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
+ int bsreg, brindex;
+ u64 pci_addr;
+
+ if(bustype == 0) {
+ /* Config space cookie, nothing to do. */
+ if(preg != 0)
+ prom_printf("fixup_doit: strange, config space not 0\n");
+ continue;
+ } else if(bustype == 3) {
+ /* XXX add support for this... */
+ prom_printf("fixup_doit: Warning, ignoring 64-bit PCI "
+ "memory space, tell DaveM.\n");
+ continue;
+ }
+ bsreg = (pregs[preg].phys_hi & 0xff);
+
+ /* We can safely ignore these. */
+ if(bsreg == PCI_ROM_ADDRESS)
+ continue;
+
+ /* Sanity */
+ if((bsreg < PCI_BASE_ADDRESS_0) ||
+ (bsreg > (PCI_BASE_ADDRESS_5 + 4)) ||
+ (bsreg & 3)) {
+ prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n",
+ bsreg);
+ continue;
+ }
+
+ brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2;
+ if(numaa) {
+ int r;
+
+ for(r = 0; r < numaa; r++) {
+ int abreg;
+
+ abreg = (assigned[r].phys_hi & 0xff);
+ if(abreg == bsreg) {
+ ap = &assigned[r];
+ break;
+ }
+ }
+ }
+
+ /* Now construct UPA physical address. */
+ pci_addr = (((u64)pregs[preg].phys_mid) << 32UL);
+ pci_addr |= (((u64)pregs[preg].phys_lo));
+
+ if(ap) {
+ pci_addr += ((u64)ap->phys_lo);
+ pci_addr += (((u64)ap->phys_mid) << 32UL);
+ }
+
+ /* Final step, apply PBM range. */
+ for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp = &pbm->pbm_ranges[rng];
+ int space = (rp->child_phys_hi >> 24) & 3;
+
+ if(space == bustype) {
+ pci_addr += ((u64)rp->parent_phys_lo);
+ pci_addr += (((u64)rp->parent_phys_hi) << 32UL);
+ break;
+ }
+ }
+ if(rng == pbm->num_pbm_ranges) {
+ /* AIEEE */
+ prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
+ }
+ pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
+
+ /* Preserve I/O space bit. */
+ if(bustype == 0x1) {
+ pdev->base_address[brindex] |= 1;
+ IO_seen = 1;
+ } else {
+ MEM_seen = 1;
+ }
+ }
+
+ /* Now handle assignments PROM did not take care of. */
+ if(nregs) {
+ int breg;
+
+ for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
+ unsigned int rtmp, ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
+ unsigned int base = (unsigned int)pdev->base_address[ridx];
+ struct pci_vma *vp;
+ u64 pci_addr;
+ int io;
+
+ if(pdev->base_address[ridx] > PAGE_OFFSET)
+ continue;
+
+ io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+ base &= ~((io ?
+ PCI_BASE_ADDRESS_IO_MASK :
+ PCI_BASE_ADDRESS_MEM_MASK));
+ vp = pci_find_vma(pbm, base, io);
+ if(!vp || vp->start > base) {
+ unsigned int size, new_base;
+
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, &rtmp);
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, 0xffffffff);
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, &size);
+ if(io)
+ size &= ~1;
+ size = (~(size) + 1);
+ if(!size)
+ continue;
+
+ new_base = 0;
+ for(vp=pci_find_vma(pbm,new_base,io); ; vp=vp->next) {
+ if(!vp || new_base + size <= vp->start)
+ break;
+ new_base = (vp->end + (size - 1)) & ~(size-1);
+ }
+ if(vp && (new_base + size > vp->start)) {
+ prom_printf("PCI: Impossible full %s space.\n",
+ (io ? "IO" : "MEM"));
+ prom_halt();
+ }
+ vp = pci_vma_alloc();
+ vp->start = new_base;
+ vp->end = vp->start + size;
+ vp->base_reg = breg;
+
+ /* Sanity */
+ if(io && vp->end & ~(0xffff)) {
+ prom_printf("PCI: Out of range PCI I/O "
+ "[%08lx:%08lx] during fixup\n",
+ vp->start, vp->end);
+ prom_halt();
+ }
+ pci_add_vma(pbm, vp, io);
+
+ rtmp = new_base;
+ if(io)
+ rtmp |= (rtmp & PCI_BASE_ADDRESS_IO_MASK);
+ else
+ rtmp |= (rtmp & PCI_BASE_ADDRESS_MEM_MASK);
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ breg, rtmp);
+
+ /* Apply PBM ranges and update pci_dev. */
+ pci_addr = new_base;
+ for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp;
+ int rspace;
+
+ rp = &pbm->pbm_ranges[rng];
+ rspace = (rp->child_phys_hi >> 24) & 3;
+ if(io && rspace != 1)
+ continue;
+ else if(!io && rspace != 2)
+ continue;
+ pci_addr += ((u64)rp->parent_phys_lo);
+ pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+ break;
+ }
+ if(rng == pbm->num_pbm_ranges) {
+ /* AIEEE */
+ prom_printf("fixup_doit: YIEEE, cannot find "
+ "PBM ranges\n");
+ }
+ pdev->base_address[ridx] = (unsigned long)__va(pci_addr);
+
+ /* Preserve I/O space bit. */
+ if(io) {
+ pdev->base_address[ridx] |= 1;
+ IO_seen = 1;
+ } else {
+ MEM_seen = 1;
+ }
+ }
+ }
+ }
+ if(IO_seen || MEM_seen) {
+ unsigned int l;
+
+ pcibios_read_config_dword(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, &l);
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("[");
+#endif
+ if(IO_seen) {
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("IO ");
+#endif
+ l |= PCI_COMMAND_IO;
+ }
+ if(MEM_seen) {
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("MEM");
+#endif
+ l |= PCI_COMMAND_MEMORY;
+ }
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("]");
+#endif
+ pcibios_write_config_dword(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, l);
+ }
+
+#ifdef FIXUP_REGS_DEBUG
+ prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device));
+ for(preg = 0; preg < 6; preg++) {
+ if(pdev->base_address[preg] != 0)
+ prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]);
+ }
+ prom_printf("\n");
+#endif
+}
+
+#define imap_offset(__member) \
+ ((unsigned long)(&(((struct psycho_regs *)0)->__member)))
+
+static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus, slot;
+
+ bus = (ino & 0x10) >> 4;
+ slot = (ino & 0x0c) >> 2;
+
+ if(bus == 0) {
+ /* Perform a sanity check, we might as well.
+ * PBM A only has 2 PCI slots.
+ */
+ if(slot > 1) {
+ prom_printf("pcislot_imap: Bogus slot on PBM A (%ld)\n", slot);
+ prom_halt();
+ }
+ if(slot == 0)
+ return imap_offset(imap_a_slot0);
+ else
+ return imap_offset(imap_a_slot1);
+ } else {
+ switch(slot) {
+ case 0:
+ return imap_offset(imap_b_slot0);
+ case 1:
+ return imap_offset(imap_b_slot1);
+ case 2:
+ return imap_offset(imap_b_slot2);
+ case 3:
+ return imap_offset(imap_b_slot3);
+ default:
+ prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
+ bus, slot);
+ prom_halt();
+ return 0; /* Make gcc happy */
+ };
+ }
+}
+
+/* Exported for EBUS probing layer. */
+unsigned int psycho_irq_build(unsigned int full_ino)
+{
+ unsigned long imap_off, ign, ino;
+
+ ign = (full_ino & PSYCHO_IMAP_IGN) >> 6;
+ ino = (full_ino & PSYCHO_IMAP_INO);
+
+ /* Compute IMAP register offset, generic IRQ layer figures out
+ * the ICLR register address as this is simple given the 32-bit
+ * irq number and IMAP register address.
+ */
+ if((ino & 0x20) == 0)
+ imap_off = psycho_pcislot_imap_offset(ino);
+ else {
+ switch(ino) {
+ case 0x20:
+ /* Onboard SCSI. */
+ imap_off = imap_offset(imap_scsi);
+ break;
+
+ case 0x21:
+ /* Onboard Ethernet (ie. CheerIO/HME) */
+ imap_off = imap_offset(imap_eth);
+ break;
+
+ case 0x22:
+ /* Onboard Parallel Port */
+ imap_off = imap_offset(imap_bpp);
+ break;
+
+ case 0x23:
+ /* Audio Record */
+ imap_off = imap_offset(imap_au_rec);
+ break;
+
+ case 0x24:
+ /* Audio Play */
+ imap_off = imap_offset(imap_au_play);
+ break;
+
+ case 0x25:
+ /* Power Fail */
+ imap_off = imap_offset(imap_pfail);
+ break;
+
+ case 0x26:
+ /* Onboard KBD/MOUSE/SERIAL */
+ imap_off = imap_offset(imap_kms);
+ break;
+
+ case 0x27:
+ /* Floppy (ie. fdthree) */
+ imap_off = imap_offset(imap_flpy);
+ break;
+
+ case 0x28:
+ /* Spare HW INT */
+ imap_off = imap_offset(imap_shw);
+ break;
+
+ case 0x29:
+ /* Onboard Keyboard (only) */
+ imap_off = imap_offset(imap_kbd);
+ break;
+
+ case 0x2a:
+ /* Onboard Mouse (only) */
+ imap_off = imap_offset(imap_ms);
+ break;
+
+ case 0x2b:
+ /* Onboard Serial (only) */
+ imap_off = imap_offset(imap_ser);
+ break;
+
+ case 0x32:
+ /* Power Management */
+ imap_off = imap_offset(imap_pmgmt);
+ break;
+
+ default:
+ /* We don't expect anything else. The other possible
+ * values are not found in PCI device nodes, and are
+ * so hardware specific that they should use DCOOKIE's
+ * anyways.
+ */
+ prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ };
+ }
+ imap_off -= imap_offset(imap_a_slot0);
+
+ return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino);
+}
+
+/* #define FIXUP_IRQ_DEBUG */
+
+static void fixup_irq(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ int node)
+{
+ unsigned int prom_irq, portid = pbm->parent->upa_portid;
+ unsigned char pci_irq_line = pdev->irq;
+ int err;
+
+#ifdef FIXUP_IRQ_DEBUG
+ printk("fixup_irq[%s:%s]: ",
+ pci_strvendor(pdev->vendor),
+ pci_strdev(pdev->vendor, pdev->device));
+#endif
+ err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
+ if(err == 0 || err == -1) {
+ prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n",
+ pci_strvendor(pdev->vendor),
+ pci_strdev(pdev->vendor, pdev->device));
+ prom_halt();
+ }
+
+ /* See if fully specified already (ie. for onboard devices like hme) */
+ if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+ pdev->irq = psycho_irq_build(prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+ printk("fully specified prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
+#endif
+ } else {
+ unsigned int bus, slot, line;
+
+ bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
+ line = (pci_irq_line) & 3;
+
+ /* Slot determination is only slightly complex. Handle
+ * the easy case first.
+ */
+ if(pdev->bus->number == pbm->pci_first_busno) {
+ if(pbm == &pbm->parent->pbm_A)
+ slot = (pdev->devfn >> 3) - 1;
+ else
+ slot = ((pdev->devfn >> 3) >> 1) - 1;
+ } else {
+ /* Underneath a bridge, use slot number of parent
+ * bridge.
+ */
+ slot = (pdev->bus->self->devfn >> 3) - 1;
+
+ /* Use low slot number bits of child as IRQ line. */
+ line = ((pdev->devfn >> 3) & 3);
+ }
+ slot = (slot << 2);
+
+ pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) |
+ (bus | slot | line)));
+#ifdef FIXUP_IRQ_DEBUG
+ do {
+ unsigned char iline, ipin;
+
+ (void)pcibios_read_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_INTERRUPT_PIN,
+ &ipin);
+ (void)pcibios_read_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_INTERRUPT_LINE,
+ &iline);
+ printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
+ "iline[%x] ipin[%x] prom_irq[%x]",
+ portid, bus>>4, slot>>2, line, pdev->irq,
+ iline, ipin, prom_irq);
+ } while(0);
+#endif
+ }
+#ifdef FIXUP_IRQ_DEBUG
+ printk("\n");
+#endif
+}
+
+static void fixup_doit(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ int node)
+{
+ struct linux_prom_pci_registers assigned[PROMREG_MAX];
+ int numaa, err;
+
+ /* Get assigned addresses, if any. */
+ err = prom_getproperty(node, "assigned-addresses",
+ (char *)&assigned[0], sizeof(assigned));
+ if(err == 0 || err == -1)
+ numaa = 0;
+ else
+ numaa = (err / sizeof(struct linux_prom_pci_registers));
+
+ /* First, scan and fixup base registers. */
+ fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
+
+ /* Next, fixup interrupt numbers. */
+ fixup_irq(pdev, pbm, node);
+}
+
+static void fixup_pci_dev(struct pci_dev *pdev,
+ struct pci_bus *pbus,
+ struct linux_pbm_info *pbm)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ int node, nregs, err;
+
+ /* If this is a PCI bridge, we must program it. */
+ if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
+ unsigned short cmd;
+
+ /* First, enable bus mastering. */
+ pcibios_read_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number,
+ pdev->devfn,
+ PCI_COMMAND, cmd);
+
+ /* Now, set cache line size to 64-bytes. */
+ pcibios_write_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_CACHE_LINE_SIZE, 64);
+ }
+
+ /* Ignore if this is one of the PBM's, EBUS, or a
+ * sub-bridge underneath the PBM. We only need to fixup
+ * true devices.
+ */
+ if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
+ (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
+ (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
+ (pcp == NULL))
+ return;
+
+ node = pcp->prom_node;
+
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == 0 || err == -1) {
+ prom_printf("Cannot find REG for pci_dev\n");
+ prom_halt();
+ }
+
+ nregs = (err / sizeof(pregs[0]));
+
+ fixup_doit(pdev, pbm, &pregs[0], nregs, node);
+}
+
+static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+{
+ struct pci_dev *pdev;
+
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ fixup_pci_dev(pdev, pbus, pbm);
+
+ for(pbus = pbus->children; pbus; pbus = pbus->children)
+ fixup_pci_bus(pbus, pbm);
+}
+
+static void fixup_addr_irq(struct linux_pbm_info *pbm)
+{
+ struct pci_bus *pbus = &pbm->pci_bus;
+
+ /* Work through top level devices (not bridges, those and their
+ * devices are handled specially in the next loop).
+ */
+ fixup_pci_bus(pbus, pbm);
+}
+
+/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
+ * We use OBP for most of this work.
+ */
+static void psycho_final_fixup(struct linux_psycho *psycho)
+{
+ /* Second, fixup base address registers and IRQ lines... */
+ fixup_addr_irq(&psycho->pbm_A);
+ fixup_addr_irq(&psycho->pbm_B);
+
+#if 0
+ prom_halt();
+#endif
+}
+
+unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+{
+ struct linux_psycho *psycho = psycho_root;
+
+ pci_probe_enable = 1;
+
+ /* XXX Really this should be per-PSYCHO, but the config space
+ * XXX reads and writes give us no way to know which PSYCHO
+ * XXX in which the config space reads should occur.
+ * XXX
+ * XXX Further thought says that we cannot change this generic
+ * XXX interface, else we'd break xfree86 and other parts of the
+ * XXX kernel (but whats more important is breaking userland for
+ * XXX the ix86/Alpha/etc. people). So we should define our own
+ * XXX internal extension initially, we can compile our own user
+ * XXX apps that need to get at PCI configuration space.
+ */
+
+ /* Probe busses under PBM A. */
+ pbm_probe(&psycho->pbm_A, &memory_start);
+
+ /* Probe busses under PBM B. */
+ pbm_probe(&psycho->pbm_B, &memory_start);
+
+ pci_init_alloc_init(&memory_start);
+
+ /* Walk all PCI devices found. For each device, and
+ * PCI bridge which is not one of the PSYCHO PBM's, fill in the
+ * sysdata with a pointer to the PBM (for pci_bus's) or
+ * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
+ */
+ fill_in_pbm_cookies(&psycho->pbm_A);
+ fill_in_pbm_cookies(&psycho->pbm_B);
+
+ /* See what OBP has taken care of already. */
+ record_assignments(&psycho->pbm_A);
+ record_assignments(&psycho->pbm_B);
+
+ /* Now, fix it all up. */
+ psycho_final_fixup(psycho);
+
+ pci_init_alloc_fini();
+
+ return ebus_init(memory_start, memory_end);
+}
+
+/* "PCI: The emerging standard..." 8-( */
+volatile int pci_poke_in_progress = 0;
+volatile int pci_poke_faulted = 0;
+
+/* XXX Current PCI support code is broken, it assumes one master PCI config
+ * XXX space exists, on Ultra we can have many of them, especially with
+ * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
+ */
+static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
+ unsigned char where)
+{
+ unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+
+ ret |= (1 << 24);
+ ret |= ((bus & 0xff) << 16);
+ ret |= ((device_fn & 0xff) << 8);
+ ret |= (where & 0xfc);
+ return (unsigned char *)ret;
+}
+
+static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+{
+ return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
+ (bus == 1 && PCI_SLOT(device_fn) > 6) ||
+ (pci_probe_enable == 0));
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xff;
+ break;
+ case 1:
+ *value = (word >> 8) & 0xff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xff;
+ break;
+ case 3:
+ *value = (word >> 24) & 0xff;
+ break;
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped) {
+ switch(where & 3) {
+ case 0:
+ *value = word & 0xffff;
+ break;
+ case 2:
+ *value = (word >> 16) & 0xffff;
+ break;
+ default:
+ printk("pcibios_read_config_word: misaligned "
+ "reg [%x]\n", where);
+ break;
+ };
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+ unsigned int word, trapped;
+
+ *value = 0xffffffff;
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ trapped = pci_poke_faulted;
+ pci_poke_faulted = 0;
+ if(!trapped)
+ *value = word;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+
+ /* Endianness doesn't matter but we have to get the memory
+ * barriers in there so...
+ */
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stba %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stha %0, [%1] %2\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+
+ if(out_of_range(bus, device_fn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_poke_in_progress = 1;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stwa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (value), "r" (addr), "i" (ASI_PL));
+ pci_poke_in_progress = 0;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, buf);
+ break;
+ case 2:
+ pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, buf);
+ break;
+ case 4:
+ pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, buf);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ int err = 0;
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ err = get_user(ubyte, (unsigned char *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ubyte);
+ break;
+
+ case 2:
+ err = get_user(ushort, (unsigned short *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, ushort);
+ break;
+
+ case 4:
+ err = get_user(uint, (unsigned int *)buf);
+ if(err)
+ break;
+ pcibios_write_config_byte(bus, dfn, off, uint);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+
+ };
+ unlock_kernel();
+
+ return err;
+}
+
+#endif
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index ac91df894..3df35ef14 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -609,10 +609,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long tmp;
int res;
-#if 0
- /* XXX Find out what is really going on. */
- flush_cache_all();
-#endif
/* Non-word alignment _not_ allowed on Sparc. */
if (current->tss.flags & SPARC_FLAG_32BIT) {
unsigned int x;
@@ -1055,7 +1051,7 @@ asmlinkage void syscall_trace(void)
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
current->tss.flags ^= MAGIC_CONSTANT;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
@@ -1067,9 +1063,9 @@ asmlinkage void syscall_trace(void)
current->pid, current->exit_code);
#endif
if (current->exit_code) {
- /* spin_lock_irq(&current->sigmask_lock); */
+ spin_lock_irq(&current->sigmask_lock);
current->signal |= (1 << (current->exit_code - 1));
- /* spin_unlock_irq(&current->sigmask_lock); */
+ spin_unlock_irq(&current->sigmask_lock);
}
current->exit_code = 0;
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 9f087a969..a3ac093f3 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
+/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -36,13 +36,29 @@ rtrap: sethi %hi(bh_active), %l2
andn %l1, %l4, %l1
be,pt %icc, to_user
andn %l7, PSTATE_IE, %l7
-rt_continue: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
- ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
- ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
- brnz,pn %l2, rt_fpu_restore
- ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
-rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
+ ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
+ andcc %l2, FPRS_FEF, %g0
+ be,pt %icc, rt_continue
+ and %l2, FPRS_DL, %l6
+ wr %g0, FPRS_FEF, %fprs
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %g5
+ membar #StoreLoad | #LoadLoad
+ brz,pn %l6, 1f
+ wr %g0, ASI_BLK_P, %asi
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+1: andcc %l2, FPRS_DU, %g0
+ be,pn %icc, 1f
+ wr %g5, 0, %gsr
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
+1: membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
+ ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
+ ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
mov %g6, %l6
ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4
ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5
@@ -69,10 +85,12 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
wrpr %l1, %g0, %tstate
wrpr %l2, %g0, %tpc
+ wrpr %o2, %g0, %tnpc
mov PRIMARY_CONTEXT, %l7
brnz,pn %l3, kern_rtt
- wrpr %o2, %g0, %tnpc
+ mov SECONDARY_CONTEXT, %l5
stxa %l0, [%l7] ASI_DMMU
+ stxa %l0, [%l5] ASI_DMMU
flush %l6
rdpr %wstate, %l1
@@ -88,10 +106,14 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
retry
kern_rtt: restore
retry
-to_user: sethi %hi(need_resched), %l0
- ld [%l0 + %lo(need_resched)], %l0
+to_user: lduw [%g6 + AOFF_task_processor], %o0
+ mov 1, %o1
+ sethi %hi(need_resched), %l0
+ ldx [%l0 + %lo(need_resched)], %l0
+ sllx %o1, %o0, %o1
wrpr %l7, PSTATE_IE, %pstate
- brz,pt %l0, check_signal
+ andcc %o1, %l0, %g0
+ be,pt %xcc, check_signal
ldx [%g6 + AOFF_task_signal], %l0
call schedule
@@ -99,36 +121,123 @@ to_user: sethi %hi(need_resched), %l0
ldx [%g6 + AOFF_task_signal], %l0
nop
check_signal: ldx [%g6 + AOFF_task_blocked], %o0
+ ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
andncc %l0, %o0, %g0
be,pt %xcc, check_user_wins
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
-check_user_wins:
- brz,pt %o2, rt_continue
- nop
+check_user_wins:brz,pt %o2, 1f
+ sethi %hi(TSTATE_PEF), %o3
call fault_in_user_windows
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ba,a,pt %xcc, rt_continue
-rt_fpu_restore: wr %g0, FPRS_FEF, %fprs
- add %sp, PTREGS_OFF + TRACEREG_SZ, %g4
- wr %g0, ASI_BLK_P, %asi
+ sethi %hi(TSTATE_PEF), %o3
+1: andcc %l2, FPRS_FEF, %g0
+ be,a,pt %icc, rt_continue
+ andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3
+ ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2
+ wr %g0, FPRS_FEF, %fprs
+ wr %o3, 0, %gsr
+ andcc %l2, SPARC_FLAG_USEDFPUL, %g0
+ bne,pn %icc, 2f
+ andcc %l2, SPARC_FLAG_USEDFPUU, %g0
+ fzero %f0
+ bne,pn %icc, 1f
+ fzero %f2
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ faddd %f0, %f2, %f32
+ fmuld %f0, %f2, %f34
+ faddd %f0, %f2, %f36
+ fmuld %f0, %f2, %f38
+ faddd %f0, %f2, %f40
+ fmuld %f0, %f2, %f42
+ faddd %f0, %f2, %f44
+ fmuld %f0, %f2, %f46
+ faddd %f0, %f2, %f48
+ fmuld %f0, %f2, %f50
+ faddd %f0, %f2, %f52
+ fmuld %f0, %f2, %f54
+ faddd %f0, %f2, %f56
+ fmuld %f0, %f2, %f58
+ faddd %f0, %f2, %f60
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+1: wr %g0, ASI_BLK_P, %asi
membar #StoreLoad | #LoadLoad
- ldda [%g4 + 0x000] %asi, %f0
- ldda [%g4 + 0x040] %asi, %f16
- ldda [%g4 + 0x080] %asi, %f32
- ldda [%g4 + 0x0c0] %asi, %f48
- ldx [%g4 + 0x100], %fsr
- ldx [%g4 + 0x108], %g3
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+2: membar #StoreLoad | #LoadLoad
+ andcc %l2, SPARC_FLAG_USEDFPUU, %g0
+ bne,pt %icc, 3f
+ wr %g0, ASI_BLK_P, %asi
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+ fzero %f32
+ fzero %f34
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
+3: ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
+ ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
membar #Sync
+ ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ba,pt %xcc, rt_continue
+ wr %g0, FPRS_FEF, %fprs
- b,pt %xcc, rt_after_fpu
- wr %g3, 0, %gsr
#undef PTREGS_OFF
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 7eb47e976..147c6e55d 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
+/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -233,8 +233,6 @@ extern unsigned ramdisk_size;
extern int root_mountflags;
-extern void register_console(void (*proc)(const char *));
-
char saved_command_line[256];
char reboot_command[256];
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index cfc55fc2e..87241f8e3 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -54,12 +54,12 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
if(tp->w_saved ||
(((unsigned long)ucp) & (sizeof(unsigned long)-1)) ||
(!__access_ok((unsigned long)ucp, sizeof(*ucp))))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
grp = &ucp->uc_mcontext.mc_gregs;
__get_user(pc, &((*grp)[MC_PC]));
__get_user(npc, &((*grp)[MC_NPC]));
if((pc | npc) & 3)
- do_exit(SIGSEGV);
+ goto do_sigsegv;
if(regs->u_regs[UREG_I1]) {
__get_user(current->blocked, &ucp->uc_sigmask);
current->blocked &= _BLOCKABLE;
@@ -67,7 +67,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
regs->tpc = pc;
regs->tnpc = npc;
__get_user(regs->y, &((*grp)[MC_Y]));
- __get_user(tstate, &((*grp)[MC_Y]));
+ __get_user(tstate, &((*grp)[MC_TSTATE]));
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
__get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
@@ -94,12 +94,23 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
__get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+ __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
__get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -109,11 +120,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
mc_gregset_t *grp;
mcontext_t *mcp;
unsigned long fp, i7;
- unsigned char fenab = (current->flags & PF_USEDFPU);
+ unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU);
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
mcp = &ucp->uc_mcontext;
grp = &mcp->mc_gregs;
@@ -150,12 +161,30 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
__put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&(mcp->mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr));
__put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
- __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
+ __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/*
@@ -233,11 +262,19 @@ static inline void
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ __get_user(fprs, &fpu->si_fprs);
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &fpu->si_fsr);
__get_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
void do_sigreturn(struct pt_regs *regs)
@@ -304,11 +341,26 @@ static inline void
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &fpu->si_fsr);
__put_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = 0;
+ __put_user(fprs, &fpu->si_fprs);
+ regs->tstate &= ~TSTATE_PEF;
}
static inline void
@@ -321,7 +373,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->flags & PF_USEDFPU))
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct new_signal_frame *)
@@ -339,7 +391,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 2. Save the current process state */
copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
- if (current->flags & PF_USEDFPU) {
+ if (current->tss.flags & SPARC_FLAG_USEDFPU) {
save_fpu_state(regs, &sf->fpu_state);
__put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
@@ -452,7 +504,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -498,7 +550,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 5135c2ae5..16cec2a72 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
+/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -117,9 +117,17 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs + 1);
- copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ __get_user(fprs, &fpu->si_fprs);
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &fpu->si_fsr);
__get_user(fpregs[33], &fpu->si_gsr);
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
void do_new_sigreturn32(struct pt_regs *regs)
@@ -169,8 +177,10 @@ void do_new_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
+#if 0
if (psr & PSR_EF)
- regs->fprs = FPRS_FEF;
+ regs->tstate |= TSTATE_PEF;
+#endif
__get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
@@ -273,7 +283,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &sc->sigc_psr);
__put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
@@ -318,10 +328,22 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &fpu->si_fsr);
__put_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = 0;
+ __put_user(fprs, &fpu->si_fprs);
+ regs->tstate &= ~TSTATE_PEF;
}
static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
@@ -335,7 +357,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->flags & PF_USEDFPU))
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
sigframe_size -= sizeof(__siginfo_fpu_t);
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -362,7 +384,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
__put_user(regs->tnpc, &sf->info.si_regs.npc);
__put_user(regs->y, &sf->info.si_regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &sf->info.si_regs.psr);
for (i = 0; i < 16; i++)
@@ -469,7 +491,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(regs->tpc, &((*gr) [SVR4_PC]));
__put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
psr = tstate_to_psr (regs->tstate);
- if(current->flags & PF_USEDFPU)
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
psr |= PSR_EF;
__put_user(psr, &((*gr) [SVR4_PSR]));
__put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -488,7 +510,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
/* Save the currently window file: */
/* 1. Link sfp->uc->gwins to our windows */
- __put_user(gw, &mc->gwin);
+ __put_user((u32)(long)gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext (): */
__put_user(current->tss.w_saved, &gw->count);
@@ -506,9 +528,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
*/
#if 0
for(window = 0; window < current->tss.w_saved; window++) {
- __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+ __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window );
copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
- __put_user(0, gw->winptr [window]);
+ __put_user(0, (int *)gw->winptr + window);
}
#endif
@@ -546,7 +568,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
}
asmlinkage int
-svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
+svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
@@ -555,6 +577,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
synchronize_user_stack();
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+ lock_kernel();
do_exit (SIGSEGV);
}
if(clear_user(uc, sizeof (*uc)))
@@ -571,7 +594,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
__put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
__put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
__put_user((tstate_to_psr(regs->tstate) |
- ((current->flags & PF_USEDFPU) ? PSR_EF : 0)),
+ ((current->tss.flags & SPARC_FLAG_USEDFPU) ? PSR_EF : 0)),
&uc->mcontext.greg [SVR4_PSR]);
__put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
@@ -594,7 +617,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
-asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs)
+asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
{
struct thread_struct *tp = &current->tss;
svr4_gregset_t *gr;
@@ -639,9 +662,10 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs)
__get_user(psr, &((*gr) [SVR4_PSR]));
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
+#if 0
if(psr & PSR_EF)
- regs->fprs = FPRS_FEF;
-
+ regs->tstate |= TSTATE_PEF;
+#endif
/* Restore g[1..7] and o[0..7] registers */
for (i = 0; i < 7; i++)
__get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
@@ -718,7 +742,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -764,7 +788,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 77ccf40a0..8dd471be6 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -10,11 +10,12 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <asm/head.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
-#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -33,9 +34,9 @@ volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
@@ -44,8 +45,6 @@ volatile int cpu_logical_map[NR_CPUS];
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
-static volatile int smp_commenced = 0;
-
void smp_setup(char *str, int *ints)
{
/* XXX implement me XXX */
@@ -68,45 +67,64 @@ char *smp_info(void)
void smp_store_cpu_info(int id)
{
- cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].udelay_val = loops_per_sec;
+ cpu_data[id].irq_count = 0;
+ cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK;
+ cpu_data[id].pgcache_size = 0;
+ cpu_data[id].pgd_cache = NULL;
+ cpu_data[id].pmd_cache = NULL;
+ cpu_data[id].pte_cache = NULL;
}
+extern void distribute_irqs(void);
+
void smp_commence(void)
{
- flush_cache_all();
- flush_tlb_all();
- smp_commenced = 1;
- flush_cache_all();
- flush_tlb_all();
+ distribute_irqs();
}
static void smp_setup_percpu_timer(void);
static volatile unsigned long callin_flag = 0;
+extern void inherit_locked_prom_mappings(int save_p);
+extern void cpu_probe(void);
+
void smp_callin(void)
{
int cpuid = hard_smp_processor_id();
- flush_cache_all();
- flush_tlb_all();
+ inherit_locked_prom_mappings(0);
+
+ __flush_cache_all();
+ __flush_tlb_all();
+
+ cpu_probe();
+
+ /* Master did this already, now is the time for us to do it. */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
smp_setup_percpu_timer();
+ __sti();
+
calibrate_delay();
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
- while(!task[cpuid])
- barrier();
- current = task[cpuid];
-
- while(!smp_commenced)
- barrier();
-
- __sti();
+ while(!smp_processors_ready)
+ membar("#LoadLoad");
}
extern int cpu_idle(void *unused);
@@ -130,18 +148,22 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
+static void smp_tickoffset_init(void);
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-extern unsigned long sparc64_cpu_startup;
+
+extern unsigned long smp_trampoline;
void smp_boot_cpus(void)
{
int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
+ smp_tickoffset_init();
__sti();
cpu_present_map = 0;
for(i = 0; i < linux_num_cpus; i++)
- cpu_present_map |= (1 << i);
+ cpu_present_map |= (1UL << i);
for(i = 0; i < NR_CPUS; i++) {
cpu_number_map[i] = -1;
cpu_logical_map[i] = -1;
@@ -160,23 +182,24 @@ void smp_boot_cpus(void)
if(i == boot_cpu_id)
continue;
- if(cpu_present_map & (1 << i)) {
+ if(cpu_present_map & (1UL << i)) {
+ unsigned long entry = (unsigned long)(&smp_trampoline);
struct task_struct *p;
int timeout;
+ entry -= KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
+ callin_flag = 0;
prom_startcpu(linux_cpus[i].prom_node,
- ((unsigned long)&sparc64_cpu_startup),
- ((unsigned long)p));
+ entry, ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
- if(cpu_callin_map[i])
+ if(callin_flag)
break;
udelay(100);
}
- if(cpu_callin_map[i]) {
- /* XXX fix this */
+ if(callin_flag) {
cpu_number_map[i] = i;
cpu_logical_map[i] = i;
} else {
@@ -184,19 +207,19 @@ void smp_boot_cpus(void)
printk("Processor %d is stuck.\n", i);
}
}
- if(!(cpu_callin_map[i])) {
- cpu_present_map &= ~(1 << i);
+ if(!callin_flag) {
+ cpu_present_map &= ~(1UL << i);
cpu_number_map[i] = -1;
}
}
if(cpucount == 0) {
printk("Error: only one processor found.\n");
- cpu_present_map = (1 << smp_processor_id());
+ cpu_present_map = (1UL << smp_processor_id());
} else {
unsigned long bogosum = 0;
for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1 << i))
+ if(cpu_present_map & (1UL << i))
bogosum += cpu_data[i].udelay_val;
}
printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -207,27 +230,39 @@ void smp_boot_cpus(void)
smp_num_cpus = cpucount + 1;
}
smp_processors_ready = 1;
+ membar("#StoreStore | #StoreLoad");
}
-/* XXX deprecated interface... */
+/* We don't even need to do anything, the only generic message pass done
+ * anymore is to stop all cpus during a panic(). When the user drops to
+ * the PROM prompt, the firmware will send the other cpu's it's MONDO
+ * vector anyways, so doing anything special here is pointless.
+ *
+ * This whole thing should go away anyways...
+ */
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- printk("smp_message_pass() called, this is bad, spinning.\n");
- __sti();
- while(1)
- barrier();
}
+/* #define XCALL_DEBUG */
+
static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
{
- u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
-
+ u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+ int stuck;
+
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
+ smp_processor_id(), data0, data1, data2, target);
+#endif
+again:
__asm__ __volatile__("
wrpr %0, %1, %%pstate
wr %%g0, %2, %%asi
stxa %3, [0x40] %%asi
stxa %4, [0x50] %%asi
stxa %5, [0x60] %%asi
+ membar #Sync
stxa %%g0, [%6] %%asi
membar #Sync"
: /* No outputs */
@@ -235,27 +270,46 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, in
"r" (data0), "r" (data1), "r" (data2), "r" (target));
/* NOTE: PSTATE_IE is still clear. */
+ stuck = 100000;
do {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (result)
: "i" (ASI_INTR_DISPATCH_STAT));
+ if(result == 0) {
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ return;
+ }
+ stuck -= 1;
+ if(stuck == 0)
+ break;
} while(result & 0x1);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
+ if(stuck == 0) {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+ smp_processor_id(), result);
+#endif
+ } else {
+#ifdef XCALL_DEBUG
+ printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
+#endif
+ udelay(2);
+ goto again;
+ }
}
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i))
+ if(mask & (1UL << i))
xcall_deliver(data0, data1, data2, pstate, i);
}
/* NOTE: Caller runs local copy on master. */
@@ -266,7 +320,14 @@ extern unsigned long xcall_flush_tlb_page;
extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_range;
extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_tlbcachesync;
extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_report_regs;
+
+void smp_report_regs(void)
+{
+ smp_cross_call(&xcall_report_regs, 0, 0, 0);
+}
void smp_flush_cache_all(void)
{
@@ -280,11 +341,33 @@ void smp_flush_tlb_all(void)
__flush_tlb_all();
}
+static void smp_cross_call_avoidance(struct mm_struct *mm)
+{
+ spin_lock(&scheduler_lock);
+ get_new_mmu_context(mm, &tlb_context_cache);
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if(current->tss.current_ds) {
+ u32 ctx = mm->context & 0x1fff;
+
+ current->tss.ctx = ctx;
+ spitfire_set_secondary_context(ctx);
+ __asm__ __volatile__("flush %g6");
+ }
+ spin_unlock(&scheduler_lock);
+}
+
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+local_flush_and_out:
__flush_tlb_mm(ctx);
}
@@ -292,22 +375,101 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+ smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+local_flush_and_out:
__flush_tlb_range(ctx, start, end);
}
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+ if(mm == current->mm && mm->count == 1) {
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ return smp_cross_call_avoidance(mm);
+ }
+#if 0 /* XXX Disabled until further notice... */
+ else if(mm != current->mm && mm->count == 1) {
+ /* Try to handle two special cases to avoid cross calls
+ * in common scenerios where we are swapping process
+ * pages out.
+ */
+ if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+ return; /* It's dead, nothing to do. */
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+ goto local_flush_and_out;
+ }
+#endif
+ smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+
+local_flush_and_out:
__flush_tlb_page(ctx, page);
}
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+/* CPU capture. */
+#define CAPTURE_DEBUG
+extern unsigned long xcall_capture;
+
+static atomic_t smp_capture_depth = ATOMIC_INIT(0);
+static atomic_t smp_capture_registry = ATOMIC_INIT(0);
+static unsigned long penguins_are_doing_time = 0;
+
+void smp_capture(void)
+{
+ int result = atomic_add_return(1, &smp_capture_depth);
+
+ membar("#StoreStore | #LoadStore");
+ if(result == 1) {
+ int ncpus = smp_num_cpus;
+
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+#endif
+ penguins_are_doing_time = 1;
+ membar("#StoreStore | #LoadStore");
+ atomic_inc(&smp_capture_registry);
+ smp_cross_call(&xcall_capture, 0, 0, 0);
+ while(atomic_read(&smp_capture_registry) != ncpus)
+ membar("#LoadLoad");
+#ifdef CAPTURE_DEBUG
+ printk("done\n");
+#endif
+ }
+}
+
+void smp_release(void)
+{
+ if(atomic_dec_and_test(&smp_capture_depth)) {
+#ifdef CAPTURE_DEBUG
+ printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+ smp_processor_id());
+#endif
+ penguins_are_doing_time = 0;
+ membar("#StoreStore | #StoreLoad");
+ atomic_dec(&smp_capture_registry);
+ }
+}
+
+/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
+ * can service tlb flush xcalls...
+ */
+void smp_penguin_jailcell(void)
+{
+ flushw_user();
+ atomic_inc(&smp_capture_registry);
+ membar("#StoreLoad | #StoreStore");
+ while(penguins_are_doing_time)
+ membar("#LoadLoad");
+ atomic_dec(&smp_capture_registry);
+}
static inline void sparc64_do_profile(unsigned long pc)
{
@@ -317,59 +479,100 @@ static inline void sparc64_do_profile(unsigned long pc)
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
- spin_lock(&ticker_lock);
- if(pc < prof_len)
- prof_buffer[pc]++;
- else
- prof_buffer[prof_len - 1]++;
- spin_unlock(&ticker_lock);
+ if(pc >= prof_len)
+ pc = prof_len - 1;
+ atomic_inc((atomic_t *)&prof_buffer[pc]);
}
}
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+static unsigned long real_tick_offset, current_tick_offset;
+
+#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier
+#define prof_counter(__cpu) cpu_data[(__cpu)].counter
extern void update_one_process(struct task_struct *p, unsigned long ticks,
unsigned long user, unsigned long system);
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
+ unsigned long compare, tick;
int cpu = smp_processor_id();
int user = user_mode(regs);
- /* XXX clear_profile_irq(cpu); */
- if(!user)
- sparc64_do_profile(regs->tpc);
- if(!--prof_counter[cpu]) {
- if(current->pid) {
- update_one_process(current, 1, user, !user);
- if(--current->counter < 0) {
- current->counter = 0;
- need_resched = 1;
- }
-
- spin_lock(&ticker_lock);
- if(user) {
- if(current->priority < DEF_PRIORITY)
- kstat.cpu_nice++;
- else
- kstat.cpu_user++;
- } else {
- kstat.cpu_system++;
+ clear_softint((1UL << 0));
+ do {
+ if(!user)
+ sparc64_do_profile(regs->tpc);
+ if(!--prof_counter(cpu)) {
+ if(current->pid) {
+ unsigned int *inc_me;
+
+ update_one_process(current, 1, user, !user);
+ if(--current->counter < 0) {
+ current->counter = 0;
+ resched_force();
+ }
+
+ if(user) {
+ if(current->priority < DEF_PRIORITY)
+ inc_me = &kstat.cpu_nice;
+ else
+ inc_me = &kstat.cpu_user;
+ } else {
+ inc_me = &kstat.cpu_system;
+ }
+ atomic_inc((atomic_t *)inc_me);
}
- spin_unlock(&ticker_lock);
+ prof_counter(cpu) = prof_multiplier(cpu);
}
- prof_counter[cpu] = prof_multiplier[cpu];
- }
+ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
+ "add %0, %2, %0\n\t"
+ "wr %0, 0x0, %%tick_cmpr\n\t"
+ "rd %%tick, %1"
+ : "=&r" (compare), "=r" (tick)
+ : "r" (current_tick_offset));
+ } while (tick >= compare);
}
static void smp_setup_percpu_timer(void)
{
- /* XXX implement me */
+ int cpu = smp_processor_id();
+
+ prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+ __asm__ __volatile__("rd %%tick, %%g1\n\t"
+ "add %%g1, %0, %%g1\n\t"
+ "wr %%g1, 0x0, %%tick_cmpr"
+ : /* no outputs */
+ : "r" (current_tick_offset)
+ : "g1");
+}
+
+static void smp_tickoffset_init(void)
+{
+ int node;
+
+ node = linux_cpus[0].prom_node;
+ real_tick_offset = prom_getint(node, "clock-frequency");
+ real_tick_offset = real_tick_offset / HZ;
+ current_tick_offset = real_tick_offset;
}
int setup_profiling_timer(unsigned int multiplier)
{
- /* XXX implement me */
+ unsigned long flags;
+ int i;
+
+ if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+ return -EINVAL;
+
+ save_and_cli(flags);
+ for(i = 0; i < NR_CPUS; i++) {
+ if(cpu_present_map & (1UL << i))
+ prof_multiplier(i) = multiplier;
+ }
+ current_tick_offset = (real_tick_offset / multiplier);
+ restore_flags(flags);
+
return 0;
}
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 990202bac..c1ceacc3f 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/in6.h>
#include <asm/oplib.h>
#include <asm/delay.h>
@@ -28,11 +29,13 @@
#include <asm/ptrace.h>
#include <asm/user.h>
#include <asm/uaccess.h>
+#include <asm/checksum.h>
#ifdef CONFIG_SBUS
#include <asm/sbus.h>
#include <asm/dma.h>
#endif
#include <asm/a.out.h>
+#include <asm/svr4.h>
struct poll {
int fd;
@@ -45,18 +48,36 @@ extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
void _sigpause_common (unsigned int set, struct pt_regs *);
extern void *__bzero_1page(void *);
extern void *__bzero(void *, size_t);
+extern void *__bzero_noasi(void *, size_t);
extern void *__memscan_zero(void *, size_t);
extern void *__memscan_generic(void *, int, size_t);
extern int __memcmp(const void *, const void *, __kernel_size_t);
extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
extern char saved_command_line[];
-
+extern char *getname32(u32 name);
+extern void linux_sparc_syscall(void);
+extern void rtrap(void);
+extern void show_regs(struct pt_regs *);
+extern void solaris_syscall(void);
+extern void syscall_trace(void);
+extern u32 sunos_sys_table[], sys_call_table32[];
+extern void tl0_solaris(void);
+extern void sys_sigsuspend(void);
+extern int sys_getppid(void);
+extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
+extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
+extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
+#ifdef __SMP__
+extern spinlock_t scheduler_lock;
+#endif
+
/* One thing to note is that the way the symbols of the mul/div
* support routines are named is a mess, they all start with
* a '.' which makes it a bitch to export, here is the trick:
@@ -70,7 +91,17 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
#ifdef __SMP__
+EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(global_bh_lock);
EXPORT_SYMBOL(klock_info);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL_PRIVATE(global_cli);
+EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+#else
+EXPORT_SYMBOL(local_irq_count);
#endif
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
@@ -81,12 +112,13 @@ EXPORT_SYMBOL(mstk48t02_regs);
EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(sparc_alloc_io);
EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(__sparc64_bh_counter);
EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
EXPORT_SYMBOL(mmu_get_scsi_sgl);
EXPORT_SYMBOL(mmu_get_scsi_one);
EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
#if CONFIG_SBUS
EXPORT_SYMBOL(SBus_chain);
EXPORT_SYMBOL(dma_chain);
@@ -139,6 +171,25 @@ EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strspn);
+#ifdef CONFIG_SOLARIS_EMUL_MODULE
+EXPORT_SYMBOL(getname32);
+EXPORT_SYMBOL(linux_sparc_syscall);
+EXPORT_SYMBOL(rtrap);
+EXPORT_SYMBOL(show_regs);
+EXPORT_SYMBOL(solaris_syscall);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(sunos_sys_table);
+EXPORT_SYMBOL(sys_call_table32);
+EXPORT_SYMBOL(tl0_solaris);
+EXPORT_SYMBOL(sys_sigsuspend);
+EXPORT_SYMBOL(sys_getppid);
+EXPORT_SYMBOL(svr4_getcontext);
+EXPORT_SYMBOL(svr4_setcontext);
+EXPORT_SYMBOL(linux_cpus);
+EXPORT_SYMBOL(sys_ioctl);
+EXPORT_SYMBOL(sys32_ioctl);
+#endif
+
/* Special internal versions of library functions. */
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
@@ -150,12 +201,13 @@ EXPORT_SYMBOL(__memcmp);
EXPORT_SYMBOL(__strncmp);
EXPORT_SYMBOL(__memmove);
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial_copy_sparc64);
/* Moving data to/from userspace. */
EXPORT_SYMBOL(__copy_to_user);
EXPORT_SYMBOL(__copy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__bzero_noasi);
/* No version information on this, heavily used in inline asm,
* and will always be 'void __ret_efault(void)'.
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index ca0faec5d..37c541755 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.2 1997/07/25 01:50:47 ralf Exp $
+/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -73,7 +73,7 @@ sys32_mremap:
.globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink
.globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate
.globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat
- .globl sys32_mkdir, sys32_mknod, sys32_utimes, sys32_ustat
+ .globl sys32_mkdir, sys32_mknod, sys32_ustat
sys32_read:
srl %o1, 0, %o1
mov %o7, %g1
@@ -202,12 +202,6 @@ sys32_mknod:
srl %o2, 16, %o2
call sys_mknod
mov %g1, %o7
-sys32_utimes:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_utimes
- mov %g1, %o7
sys32_ustat:
srl %o1, 0, %o1
mov %o7, %g1
@@ -285,24 +279,9 @@ sys32_getsockopt:
call sys_setsockopt
mov %g1, %o7
- .align 32
- .globl sys32_gettimeofday, sys32_settimeofday
-sys32_gettimeofday:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_gettimeofday
- mov %g1, %o7
-sys32_settimeofday:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_settimeofday
- mov %g1, %o7
-
.globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog
- .globl sys32_personality, sys32_waitpid, sys32_getitimer
- .globl sys32_setitimer, sys32_sched_setscheduler
+ .globl sys32_personality, sys32_waitpid
+ .globl sys32_sched_setscheduler
.globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal
.globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname
.globl sys32_sethostname, sys32_gethostname, sys32_setdomainname
@@ -338,17 +317,6 @@ sys32_waitpid:
mov %o7, %g1
call sys_waitpid
mov %g1, %o7
-sys32_getitimer:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_getitimer
- mov %g1, %o7
-sys32_setitimer:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_setitimer
- mov %g1, %o7
sys32_sched_setscheduler:
srl %o2, 0, %o2
mov %o7, %g1
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index c827df7a1..0ec6de167 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -191,9 +191,12 @@ out:
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
+ static int count=0;
lock_kernel();
- printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
- show_regs (regs);
+ if (++count <= 20) { /* Don't make the system unusable, if someone goes stuck */
+ printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
+ show_regs (regs);
+ }
unlock_kernel();
return -ENOSYS;
}
@@ -220,46 +223,36 @@ asmlinkage int
sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
{
struct sigaction new_sa, *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+ int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(&current->sig->siglock);
*p = new_sa;
check_pending(signum);
+ spin_unlock_irq(&current->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/* only AP+ systems have sys_aplib */
@@ -267,3 +260,15 @@ asmlinkage int sys_aplib(void)
{
return -ENOSYS;
}
+
+asmlinkage int solaris_syscall(struct pt_regs *regs)
+{
+ lock_kernel();
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ printk ("For Solaris binary emulation you need solaris module loaded\n");
+ show_regs (regs);
+ send_sig(SIGSEGV, current, 1);
+ unlock_kernel();
+ return 0;
+}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index b6ca9448c..e2c199f60 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.44 1997/07/20 09:18:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -44,6 +44,7 @@
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/semaphore.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.
@@ -53,6 +54,33 @@
*/
#define A(x) ((unsigned long)x)
+extern char * getname_quicklist;
+extern int getname_quickcount;
+extern struct semaphore getname_quicklock;
+extern int kerneld_msqid;
+
+/* Tuning: increase locality by reusing same pages again...
+ * if getname_quicklist becomes too long on low memory machines, either a limit
+ * should be added or after a number of cycles some pages should
+ * be released again ...
+ */
+static inline char * get_page(void)
+{
+ char * res;
+ down(&getname_quicklock);
+ res = getname_quicklist;
+ if (res) {
+ getname_quicklist = *(char**)res;
+ getname_quickcount--;
+ }
+ else
+ res = (char*)__get_free_page(GFP_KERNEL);
+ up(&getname_quicklock);
+ return res;
+}
+
+#define putname32 putname
+
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
@@ -74,44 +102,67 @@ static inline int do_getname32(u32 filename, char *page)
return retval;
}
-/* This is a single page for faster getname.
- * If the page is available when entering getname, use it.
- * If the page is not available, call __get_free_page instead.
- * This works even though do_getname can block (think about it).
- * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996.
- * We don't use the common getname/putname from namei.c, so that
- * this still works well, as every routine which calls getname32
- * will then call getname, then putname and then putname32.
- */
-static unsigned long name_page_cache32 = 0;
+char * getname32(u32 filename)
+{
+ char *tmp, *result;
+
+ result = ERR_PTR(-ENOMEM);
+ tmp = get_page();
+ if (tmp) {
+ int retval = do_getname32(filename, tmp);
-void putname32(char * name)
+ result = tmp;
+ if (retval < 0) {
+ putname32(tmp);
+ result = ERR_PTR(retval);
+ }
+ }
+ return result;
+}
+
+/* 32-bit timeval and related flotsam. */
+
+struct timeval32
{
- if (name_page_cache32 == 0)
- name_page_cache32 = (unsigned long) name;
- else
- free_page((unsigned long) name);
+ int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
}
-int getname32(u32 filename, char **result)
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
{
- unsigned long page;
- int retval;
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
- page = name_page_cache32;
- name_page_cache32 = 0;
- if (!page) {
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- }
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
- retval = do_getname32(filename, (char *) page);
- if (retval < 0)
- putname32( (char *) page );
- else
- *result = (char *) page;
- return retval;
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
}
extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
@@ -266,14 +317,25 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
switch (call) {
case MSGSND:
{
- struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) err = -ENOMEM;
else {
- if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
- err = -EFAULT;
- else {
+ err = 0;
+ if (first == kerneld_msqid) {
+ *(int *)p->mtext = 0;
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) ||
+ __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4))
+ err = -EFAULT;
+ else
+ second += 4;
+ } else {
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+ err = -EFAULT;
+ }
+ if (!err) {
unsigned long old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_msgsnd (first, p, second, third);
@@ -287,6 +349,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
{
struct msgbuf *p;
unsigned long old_fs;
+ long msgtyp = fifth;
if (!version) {
struct ipc_kludge tmp;
@@ -297,20 +360,35 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
goto out;
ptr = tmp.msgp;
- fifth = tmp.msgtyp;
+ msgtyp = tmp.msgtyp;
}
- p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+
+ p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) {
err = -EFAULT;
goto out;
}
+
old_fs = get_fs();
set_fs (KERNEL_DS);
- err = sys_msgrcv (first, p, second, fifth, third);
+ err = sys_msgrcv (first, p, second + 4, msgtyp, third);
set_fs (old_fs);
- if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second))
- err = -EFAULT;
+
+ if (err < 0)
+ goto out;
+
+ if (first == kerneld_msqid) {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8))
+ err = -EFAULT;
+ else
+ err -= 4;
+ } else {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
+ err = -EFAULT;
+ }
kfree (p);
goto out;
}
@@ -472,8 +550,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = -EINVAL;
goto out;
}
- else
- err = -EINVAL;
+
+ err = -EINVAL;
+
out:
unlock_kernel();
return err;
@@ -565,8 +644,9 @@ 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));
}
- err = getname32 (special, &spec);
- if (err) return err;
+ spec = getname32 (special);
+ err = PTR_ERR(spec);
+ if (IS_ERR(spec)) return err;
old_fs = get_fs ();
set_fs (KERNEL_DS);
err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
@@ -608,8 +688,9 @@ asmlinkage int sys32_statfs(u32 path, u32 buf)
unsigned long old_fs = get_fs();
char *pth;
- ret = getname32 (path, &pth);
- if (!ret) {
+ pth = getname32 (path);
+ ret = PTR_ERR(pth);
+ if (!IS_ERR(pth)) {
set_fs (KERNEL_DS);
ret = sys_statfs((const char *)pth, &s);
set_fs (old_fs);
@@ -651,8 +732,9 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
__get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
return -EFAULT;
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_utime(filenam, &t);
@@ -1010,7 +1092,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
lock_kernel ();
p = (char *)__get_free_page (GFP_KERNEL);
if (!p)
- goto out;
+ goto out_nofree;
q = (u32 *)p;
Inp = (u32 *)A(inp);
@@ -1019,7 +1101,13 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ret = -EFAULT;
- nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long));
+ nn = (n + (8 * sizeof(long)) - 1) / (8 * sizeof(long));
+ if (inp && verify_area(VERIFY_WRITE, Inp, nn*sizeof(long)))
+ goto out;
+ if (outp && verify_area(VERIFY_WRITE, Outp, nn*sizeof(long)))
+ goto out;
+ if (exp && verify_area(VERIFY_WRITE, Exp, nn*sizeof(long)))
+ goto out;
for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1)))
goto out;
@@ -1033,7 +1121,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ktvp = NULL;
if(tvp) {
- if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp)))
+ if (get_tv32(&kern_tv, (struct timeval32 *)A(tvp)))
goto out;
ktvp = &kern_tv;
}
@@ -1048,8 +1136,12 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
ktvp);
set_fs (old_fs);
- if(tvp && !(current->personality & STICKY_TIMEOUTS))
- copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp));
+ if(tvp && !(current->personality & STICKY_TIMEOUTS)) {
+ if (put_tv32((struct timeval32 *)A(tvp), &kern_tv)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
q = (u32 *)p;
Inp = (u32 *)A(inp);
@@ -1079,6 +1171,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
}
out:
free_page ((unsigned long)p);
+out_nofree:
unlock_kernel();
return ret;
}
@@ -1111,8 +1204,9 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
@@ -1132,8 +1226,9 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
@@ -1239,12 +1334,12 @@ static void *do_smb_super_data_conv(void *raw_data)
struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
- s->dir_mode = s32->dir_mode;
- s->file_mode = s32->file_mode;
- s->gid = s32->gid;
- s->uid = s32->uid;
- memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr)));
+ s->version = s32->version;
s->mounted_uid = s32->mounted_uid;
+ s->uid = s32->uid;
+ s->gid = s32->gid;
+ s->file_mode = s32->file_mode;
+ s->dir_mode = s32->dir_mode;
return raw_data;
}
@@ -1344,8 +1439,8 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
}
struct rusage32 {
- struct timeval ru_utime;
- struct timeval ru_stime;
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
s32 ru_maxrss;
s32 ru_ixrss;
s32 ru_idrss;
@@ -1703,7 +1798,7 @@ struct timex32 {
s32 constant;
s32 precision;
s32 tolerance;
- struct timeval time;
+ struct timeval32 time;
s32 tick;
s32 ppsfreq;
s32 jitter;
@@ -2110,54 +2205,45 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
{
struct sigaction32 new_sa, old_sa;
struct sigaction *p;
- int err = -EINVAL;
- lock_kernel();
if(signum < 0) {
current->tss.new_signal = 1;
signum = -signum;
}
-
if (signum<1 || signum>32)
- goto out;
+ return -EINVAL;
p = signum - 1 + current->sig->action;
if (action) {
- err = -EINVAL;
if (signum==SIGKILL || signum==SIGSTOP)
- goto out;
- err = -EFAULT;
+ return -EINVAL;
if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL &&
((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
- err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+ int err = verify_area(VERIFY_READ,
+ (__sighandler_t)A(new_sa.sa_handler), 1);
if (err)
- goto out;
+ return err;
}
}
-
if (oldaction) {
- err = -EFAULT;
old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
old_sa.sa_mask = (sigset_t32)(p->sa_mask);
old_sa.sa_flags = (unsigned)(p->sa_flags);
old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
- goto out;
+ return -EFAULT;
}
-
if (action) {
+ spin_lock_irq(&current->sig->siglock);
p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
p->sa_mask = (sigset_t)(new_sa.sa_mask);
p->sa_flags = new_sa.sa_flags;
p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
check_pending(signum);
+ spin_unlock_irq(&current->sig->siglock);
}
-
- err = 0;
-out:
- unlock_kernel();
- return err;
+ return 0;
}
/*
@@ -2298,7 +2384,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
base = 1;
lock_kernel();
- filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+ filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
@@ -2310,6 +2396,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
regs->fprs = 0;
+ regs->tstate &= ~TSTATE_PEF;
}
out:
unlock_kernel();
@@ -2369,8 +2456,12 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si
case QM_MODULES:
case QM_REFS:
case QM_DEPS:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
buff = kmalloc (bufsiz, GFP_KERNEL);
if (!buff) {
if (name_user) putname32 (usernam);
@@ -2431,8 +2522,12 @@ qmsym_toshort:
if (name_user) putname32 (usernam);
return ret;
case QM_INFO:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
set_fs (KERNEL_DS);
ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
set_fs (old_fs);
@@ -2720,9 +2815,7 @@ static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res
return 0;
}
-extern asmlinkage int sys_nfsservctl(int cmd,
- struct nfsctl_arg *arg,
- union nfsctl_res *resp);
+extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
{
@@ -2793,3 +2886,106 @@ done:
kfree(kres);
return err;
}
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32((struct timeval32 *)A(tv), &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, (struct timeval32 *)A(tv)))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage int sys32_getitimer(int which, u32 it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32((struct itimerval32 *)A(it), &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, (struct itimerval32 *)A(in)))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+ if (put_it32((struct itimerval32 *)A(out), &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int sys_utimes(char *, struct timeval *);
+
+asmlinkage int sys32_utimes(u32 filename, u32 tvs)
+{
+ char *kfilename;
+ struct timeval ktvs[2];
+ unsigned long old_fs;
+ int ret;
+
+ kfilename = getname32(filename);
+ ret = PTR_ERR(kfilename);
+ if (!IS_ERR(kfilename)) {
+ if (tvs) {
+ if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) ||
+ get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs)))
+ return -EFAULT;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_utimes(kfilename, &ktvs[0]);
+ set_fs(old_fs);
+
+ putname32(kfilename);
+ }
+ return ret;
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index eda0ff326..9b00175a3 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
+/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -10,213 +10,214 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
- .data
- .align 8
+ .text
+ .align 1024
/* First, the 32-bit Linux native syscall table. */
.globl sys_call_table32
sys_call_table32:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
- .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
- .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
- .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
- .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
- .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
- .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
- .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/ .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
- .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+ .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
+/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+ .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+ .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+ .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+ .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+ .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+ .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
+ .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+ .word sys_aplib
/* Now the 64-bit native Linux syscall table. */
+ .align 1024
.globl sys_call_table64, sys_call_table
sys_call_table64:
sys_call_table:
-/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
- .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
- .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
- .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
- .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
- .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
- .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
- .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/ .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
- .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
- .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
-/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
- .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
- .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/ .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
- .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
- .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
- .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
- .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
- .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
- .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
- .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
- .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
- .xword sys_aplib, sys_nis_syscall
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+ .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+ .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+ .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+ .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
+ .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+ .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+ .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
+ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+ .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+ .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+ .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+ .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+ .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+ .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+ .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+ .word sys_aplib
/* Now the 32-bit SunOS syscall table. */
- .align 8
+ .align 1024
.globl sunos_sys_table
sunos_sys_table:
-/*0*/ .xword sunos_indir, sys_exit, sys_fork
- .xword sunos_read, sunos_write, sunos_open
- .xword sys_close, sunos_wait4, sys32_creat
- .xword sys32_link, sys32_unlink, sunos_execv
- .xword sys32_chdir, sunos_nosys, sys32_mknod
- .xword sys32_chmod, sys32_chown, sunos_brk
- .xword sunos_nosys, sys32_lseek, sunos_getpid
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_getuid, sunos_nosys, sys_ptrace
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sys32_access, sunos_nosys, sunos_nosys
- .xword sys_sync, sys_kill, sys32_newstat
- .xword sunos_nosys, sys32_newlstat, sys_dup
- .xword sys_pipe, sunos_nosys, sys_profil
- .xword sunos_nosys, sunos_nosys, sunos_getgid
- .xword sunos_nosys, sunos_nosys
-/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys
- .xword sunos_mctl, sunos_ioctl, sys32_reboot
- .xword sunos_nosys, sys32_symlink, sys32_readlink
- .xword sys32_execve, sys_umask, sys32_chroot
- .xword sys32_newfstat, sunos_nosys, sys_getpagesize
- .xword sys32_msync, sys_vfork, sunos_nosys
- .xword sunos_nosys, sunos_sbrk, sunos_sstk
- .xword sunos_mmap, sunos_vadvise, sys32_munmap
- .xword sys32_mprotect, sunos_madvise, sys_vhangup
- .xword sunos_nosys, sunos_mincore, sys32_getgroups
- .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp
- .xword sys32_setitimer, sunos_nosys, sys32_swapon
- .xword sys32_getitimer, sys32_gethostname, sys32_sethostname
- .xword sunos_getdtablesize, sys_dup2, sunos_nop
- .xword sys32_fcntl, sunos_select, sunos_nop
- .xword sys_fsync, sys_setpriority, sys_socket
- .xword sys32_connect, sunos_accept
-/*100*/ .xword sys_getpriority, sunos_send, sunos_recv
- .xword sunos_nosys, sys32_bind, sunos_setsockopt
- .xword sys_listen, sunos_nosys, sunos_sigaction
- .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
- .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg
- .xword sunos_nosys, sys_gettimeofday, sys32_getrusage
- .xword sunos_getsockopt, sunos_nosys, sunos_readv
- .xword sunos_writev, sys_settimeofday, sys_fchown
- .xword sys_fchmod, sys32_recvfrom, sys32_setreuid
- .xword sys_setregid, sys32_rename, sys32_truncate
- .xword sys32_ftruncate, sys_flock, sunos_nosys
- .xword sys32_sendto, sys_shutdown, sys_socketpair
- .xword sys32_mkdir, sys32_rmdir, sys32_utimes
- .xword sys_sigreturn, sunos_nosys, sys32_getpeername
- .xword sunos_gethostid, sunos_nosys, sys32_getrlimit
- .xword sys32_setrlimit, sunos_killpg, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*150*/ .xword sys32_getsockname, sunos_nosys, sunos_nosys
- .xword sys32_poll, sunos_nosys, sunos_nosys
- .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs
- .xword sys32_umount, sunos_nosys, sunos_nosys
- .xword sunos_getdomainname, sys32_setdomainname
- .xword sunos_nosys, sys32_quotactl, sunos_nosys
- .xword sunos_mount, sys32_ustat, sunos_semsys
- .xword sunos_nosys, sunos_shmsys, sunos_audit
- .xword sunos_nosys, sunos_getdents, sys_setsid
- .xword sys_fchdir, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sys32_sigpending, sunos_nosys
- .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
- .xword sunos_sysconf, sunos_uname, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
-/*200*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys
-/*250*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
- .xword sunos_nosys, sunos_nosys, sys_aplib
+/*0*/ .word sunos_indir, sys_exit, sys_fork
+ .word sunos_read, sunos_write, sunos_open
+ .word sys_close, sunos_wait4, sys32_creat
+ .word sys32_link, sys32_unlink, sunos_execv
+ .word sys32_chdir, sunos_nosys, sys32_mknod
+ .word sys32_chmod, sys32_chown, sunos_brk
+ .word sunos_nosys, sys32_lseek, sunos_getpid
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_getuid, sunos_nosys, sys_ptrace
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sys32_access, sunos_nosys, sunos_nosys
+ .word sys_sync, sys_kill, sys32_newstat
+ .word sunos_nosys, sys32_newlstat, sys_dup
+ .word sys_pipe, sunos_nosys, sys_profil
+ .word sunos_nosys, sunos_nosys, sunos_getgid
+ .word sunos_nosys, sunos_nosys
+/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys
+ .word sunos_mctl, sunos_ioctl, sys32_reboot
+ .word sunos_nosys, sys32_symlink, sys32_readlink
+ .word sys32_execve, sys_umask, sys32_chroot
+ .word sys32_newfstat, sunos_nosys, sys_getpagesize
+ .word sys32_msync, sys_vfork, sunos_nosys
+ .word sunos_nosys, sunos_sbrk, sunos_sstk
+ .word sunos_mmap, sunos_vadvise, sys32_munmap
+ .word sys32_mprotect, sunos_madvise, sys_vhangup
+ .word sunos_nosys, sunos_mincore, sys32_getgroups
+ .word sys32_setgroups, sys_getpgrp, sunos_setpgrp
+ .word sys32_setitimer, sunos_nosys, sys32_swapon
+ .word sys32_getitimer, sys32_gethostname, sys32_sethostname
+ .word sunos_getdtablesize, sys_dup2, sunos_nop
+ .word sys32_fcntl, sunos_select, sunos_nop
+ .word sys_fsync, sys_setpriority, sys_socket
+ .word sys32_connect, sunos_accept
+/*100*/ .word sys_getpriority, sunos_send, sunos_recv
+ .word sunos_nosys, sys32_bind, sunos_setsockopt
+ .word sys_listen, sunos_nosys, sunos_sigaction
+ .word sunos_sigblock, sunos_sigsetmask, sys_sigpause
+ .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
+ .word sunos_nosys, sys32_gettimeofday, sys32_getrusage
+ .word sunos_getsockopt, sunos_nosys, sunos_readv
+ .word sunos_writev, sys32_settimeofday, sys_fchown
+ .word sys_fchmod, sys32_recvfrom, sys32_setreuid
+ .word sys_setregid, sys32_rename, sys32_truncate
+ .word sys32_ftruncate, sys_flock, sunos_nosys
+ .word sys32_sendto, sys_shutdown, sys_socketpair
+ .word sys32_mkdir, sys32_rmdir, sys32_utimes
+ .word sys_sigreturn, sunos_nosys, sys32_getpeername
+ .word sunos_gethostid, sunos_nosys, sys32_getrlimit
+ .word sys32_setrlimit, sunos_killpg, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys
+ .word sys32_poll, sunos_nosys, sunos_nosys
+ .word sunos_getdirentries, sys32_statfs, sys32_fstatfs
+ .word sys32_umount, sunos_nosys, sunos_nosys
+ .word sunos_getdomainname, sys32_setdomainname
+ .word sunos_nosys, sys32_quotactl, sunos_nosys
+ .word sunos_mount, sys32_ustat, sunos_semsys
+ .word sunos_nosys, sunos_shmsys, sunos_audit
+ .word sunos_nosys, sunos_getdents, sys_setsid
+ .word sys_fchdir, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sys32_sigpending, sunos_nosys
+ .word sys_setpgid, sunos_pathconf, sunos_fpathconf
+ .word sunos_sysconf, sunos_uname, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys
+/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sys_aplib
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index df6a1c05e..8b0152231 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
+/* $Id: time.c,v 1.12 1997/08/22 20:12:13 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -17,12 +18,17 @@
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/fhc.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
@@ -155,33 +161,55 @@ static int has_low_battery(void)
/* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+__initfunc(static void set_system_time(void))
{
- struct linux_prom_registers clk_reg[2];
- char model[128];
- int node, sbusnd, err;
-
- /* XXX HACK HACK HACK, delete me soon */
- struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
- int XXX_sbus_nranges;
+ unsigned int year, mon, day, hour, min, sec;
+ struct mostek48t02 *mregs;
- node = prom_getchild(prom_root_node);
- sbusnd = prom_searchsiblings(node, "sbus");
- node = prom_getchild(sbusnd);
+ do_get_fast_time = do_gettimeofday;
- if(node == 0 || node == -1) {
- prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+ mregs = mstk48t02_regs;
+ if(!mregs) {
+ prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
+ }
+
+ mregs->creg |= MSTK_CREG_READ;
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+ xtime.tv_usec = 0;
+ mregs->creg &= ~MSTK_CREG_READ;
+}
+
+__initfunc(void clock_probe(void))
+{
+ struct linux_prom_registers clk_reg[2];
+ char model[128];
+ int node, busnd = -1, err;
+
+ if(central_bus != NULL) {
+ busnd = central_bus->child->prom_node;
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain != NULL) {
+ busnd = ebus_chain->prom_node;
+ }
+#endif
+ else {
+ busnd = SBus_chain->prom_node;
}
- /* XXX FIX ME */
- err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
- sizeof(XXX_sbus_ranges));
- if(err == -1) {
- prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+ if(busnd == -1) {
+ prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
- XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+ node = prom_getchild(busnd);
while(1) {
prom_getstring(node, "model", model, sizeof(model));
@@ -199,12 +227,48 @@ __initfunc(static void clock_probe(void))
err = prom_getproperty(node, "reg", (char *)clk_reg,
sizeof(clk_reg));
if(err == -1) {
- prom_printf("clock_probe: Cannot make Mostek\n");
+ prom_printf("clock_probe: Cannot get Mostek reg property\n");
prom_halt();
}
- /* XXX fix me badly */
- prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+ if(central_bus) {
+ prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
+ prom_apply_central_ranges(central_bus, clk_reg, 1);
+ }
+#ifdef CONFIG_PCI
+ else if (ebus_chain) {
+ struct linux_ebus_device *edev;
+
+ for_each_ebusdev(edev, ebus_chain)
+ if (edev->prom_node == node)
+ break;
+ if (!edev) {
+ prom_printf("%s: Mostek not probed by EBUS\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+
+ if (check_region(edev->base_address[0],
+ sizeof(struct mostek48t59))) {
+ prom_printf("%s: Can't get region %lx, %d\n",
+ __FUNCTION__, edev->base_address[0],
+ sizeof(struct mostek48t59));
+ prom_halt();
+ }
+ request_region(edev->base_address[0],
+ sizeof(struct mostek48t59), "clock");
+
+ mstk48t59_regs = (struct mostek48t59 *)
+ edev->base_address[0];
+ mstk48t02_regs = &mstk48t59_regs->regs;
+ break;
+ }
+#endif
+ else {
+ prom_adjust_regs(clk_reg, 1,
+ SBus_chain->sbus_ranges,
+ SBus_chain->num_sbus_ranges);
+ }
if(model[5] == '0' && model[6] == '2') {
mstk48t02_regs = (struct mostek48t02 *)
@@ -234,6 +298,8 @@ __initfunc(static void clock_probe(void))
/* Kick start the clock if it is completely stopped. */
if (mstk48t02_regs->sec & MSTK_STOP)
kick_start_clock();
+
+ set_system_time();
}
#ifndef BCD_TO_BIN
@@ -246,29 +312,10 @@ __initfunc(static void clock_probe(void))
__initfunc(void time_init(void))
{
- unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
-
- do_get_fast_time = do_gettimeofday;
-
- clock_probe();
-
- mregs = mstk48t02_regs;
- if(!mregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- mregs->creg |= MSTK_CREG_READ;
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_usec = 0;
- mregs->creg &= ~MSTK_CREG_READ;
+ /* clock_probe() is now done at end of sbus_init on sparc64
+ * so that both sbus and fhc bus information is probed and
+ * available.
+ */
}
extern void init_timers(void (*func)(int, void *, struct pt_regs *));
@@ -301,22 +348,29 @@ void do_gettimeofday(struct timeval *tv)
/* Load doubles must be used on xtime so that what we get
* is guarenteed to be atomic, this is why we can run this
* with interrupts on full blast. Don't touch this... -DaveM
+ *
+ * Note with time_t changes to the timeval type, I must now use
+ * nucleus atomic quad 128-bit loads.
*/
__asm__ __volatile__("
sethi %hi(linux_timers), %o1
sethi %hi(xtime), %g2
ldx [%o1 + %lo(linux_timers)], %g3
-1: ldd [%g2 + %lo(xtime)], %o4
+ or %g2, %lo(xtime), %g2
+1: ldda [%g2] 0x24, %o4
+ membar #LoadLoad | #MemIssue
ldx [%g3], %o1
- ldd [%g2 + %lo(xtime)], %o2
+ membar #LoadLoad | #MemIssue
+ ldda [%g2] 0x24, %o2
+ membar #LoadLoad
xor %o4, %o2, %o2
xor %o5, %o3, %o3
orcc %o2, %o3, %g0
- bne,pn %icc, 1b
+ bne,pn %xcc, 1b
cmp %o1, 0
bge,pt %icc, 1f
sethi %hi(tick), %o3
- ld [%o3 + %lo(tick)], %o3
+ ldx [%o3 + %lo(tick)], %o3
sethi %hi(0x1fffff), %o2
or %o2, %lo(0x1fffff), %o2
add %o5, %o3, %o5
@@ -325,12 +379,12 @@ void do_gettimeofday(struct timeval *tv)
sethi %hi(1000000), %o2
or %o2, %lo(1000000), %o2
cmp %o5, %o2
- bl,a,pn %icc, 1f
- st %o4, [%o0 + 0x0]
+ bl,a,pn %xcc, 1f
+ stx %o4, [%o0 + 0x0]
add %o4, 0x1, %o4
sub %o5, %o2, %o5
- st %o4, [%o0 + 0x0]
-1: st %o5, [%o0 + 0x4]");
+ stx %o4, [%o0 + 0x0]
+1: stx %o5, [%o0 + 0x8]");
}
void do_settimeofday(struct timeval *tv)
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
new file mode 100644
index 000000000..cefcb6ba3
--- /dev/null
+++ b/arch/sparc64/kernel/trampoline.S
@@ -0,0 +1,207 @@
+/* $Id: trampoline.S,v 1.2 1997/08/30 04:53:05 ralf Exp $
+ * trampoline.S: Jump start slave processors on sparc64.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
+#include <asm/pstate.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/spitfire.h>
+#include <asm/asm_offsets.h>
+
+ .data
+ .align 8
+ .globl smp_trampoline
+smp_trampoline: .skip 0x300
+
+ .text
+ .align 8
+ .globl sparc64_cpu_startup, sparc64_cpu_startup_end
+sparc64_cpu_startup:
+ flushw
+ mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+ wrpr %g0, 15, %pil
+
+ sethi %uhi(PAGE_OFFSET), %g4
+ sllx %g4, 32, %g4
+
+ /* XXX Buggy PROM... */
+ srl %o0, 0, %g6
+ add %g6, %g4, %g6
+
+ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+ sllx %g5, 32, %g5
+ or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+ sethi %uhi(_PAGE_PADDR), %g3
+ or %g3, %ulo(_PAGE_PADDR), %g3
+ sllx %g3, 32, %g3
+ sethi %hi(_PAGE_PADDR), %g7
+ or %g7, %lo(_PAGE_PADDR), %g7
+ or %g3, %g7, %g3
+
+ clr %l0
+ set 0x1fff, %l2
+ rd %pc, %l3
+ andn %l3, %l2, %g2
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g2
+ be,a,pn %xcc, 2f
+ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
+ cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+2: nop
+ nop
+ nop
+ and %g1, %g3, %g1
+ sub %g1, %g2, %g1
+ or %g5, %g1, %g5
+ clr %l0
+ sethi %hi(KERNBASE), %g3
+ sethi %hi(KERNBASE<<1), %g7
+ mov TLB_TAG_ACCESS, %l7
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_IMMU
+ stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ clr %l0
+1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_DMMU
+ stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ sethi %hi(KERNBASE), %g3
+ mov (63 << 3), %g7
+ stxa %g3, [%l7] ASI_DMMU
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ stxa %g3, [%l7] ASI_IMMU
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+ flush %g3
+ membar #Sync
+ b,pt %xcc, 1f
+ nop
+1: set bounce, %g2
+ jmpl %g2 + %g0, %g0
+ nop
+
+bounce:
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ mov TLB_TAG_ACCESS, %g2
+ stxa %g3, [%g2] ASI_IMMU
+ stxa %g3, [%g2] ASI_DMMU
+
+ mov (63 << 3), %g7
+ ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+
+ ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+ flush %g3
+ membar #Sync
+
+ 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, 0, %tl
+
+ /* Setup the trap globals, then we can resurface. */
+ rdpr %pstate, %o1
+ mov %g6, %o2
+ wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate
+ sethi %hi(sparc64_ttable_tl0), %g5
+ wrpr %g5, %tba
+ mov %o2, %g6
+
+ wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
+ sethi %hi(0x1ff8), %g2
+ or %g2, %lo(0x1ff8), %g2
+ ldx [%o2 + AOFF_task_mm], %g6
+ ldx [%g6 + AOFF_mm_pgd], %g6
+ clr %g7
+
+ wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
+ sethi %hi(ivector_to_mask), %g5
+ or %g5, %lo(ivector_to_mask), %g1
+ mov 0x40, %g2
+
+ wrpr %g0, 0, %wstate
+ wrpr %o1, PSTATE_IE, %pstate
+
+ mov TSB_REG, %o4
+ mov 1, %o5
+ stxa %o5, [%o4] ASI_DMMU
+ stxa %o5, [%o4] ASI_IMMU
+ membar #Sync
+
+ or %o1, PSTATE_IE, %o1
+ wrpr %o1, 0, %pstate
+
+ call smp_callin
+ nop
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
+ nop
+1: b,a,pt %xcc, 1b
+
+ .align 8
+sparc64_cpu_startup_end:
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index ac3e79958..1ffd43730 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/lsu.h>
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
@@ -194,8 +195,55 @@ void data_access_exception (struct pt_regs *regs)
send_sig(SIGSEGV, current, 1);
}
+#ifdef CONFIG_PCI
+/* This is really pathetic... */
+/* #define DEBUG_PCI_POKES */
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+#endif
+
void do_dae(struct pt_regs *regs)
{
+#ifdef CONFIG_PCI
+#ifdef DEBUG_PCI_POKES
+ prom_printf(" (POKE ");
+#endif
+ if(pci_poke_in_progress) {
+ unsigned long va;
+#ifdef DEBUG_PCI_POKES
+ prom_printf("tpc[%016lx] tnpc[%016lx] ",
+ regs->tpc, regs->tnpc);
+#endif
+ pci_poke_faulted = 1;
+ regs->tnpc = regs->tpc + 4;
+
+
+#ifdef DEBUG_PCI_POKES
+ prom_printf("PCI) ");
+ /* prom_halt(); */
+#endif
+ /* Re-enable I/D caches, Ultra turned them off. */
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
+ spitfire_put_icache_tag(va, 0x0);
+ spitfire_put_dcache_tag(va, 0x0);
+ }
+ __asm__ __volatile__("flush %%g6\n\t"
+ "membar #Sync\n\t"
+ "stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+ LSU_CONTROL_IM | LSU_CONTROL_DM),
+ "i" (ASI_LSU_CONTROL)
+ : "memory");
+ return;
+ }
+#ifdef DEBUG_PCI_POKES
+ prom_printf("USER) ");
+ prom_printf("tpc[%016lx] tnpc[%016lx]\n");
+ prom_halt();
+#endif
+#endif
send_sig(SIGSEGV, current, 1);
}
@@ -215,11 +263,9 @@ void do_fpe_common(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
} else {
- lock_kernel();
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_FPERROR;
send_sig(SIGFPE, current, 1);
- unlock_kernel();
}
}
@@ -288,6 +334,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
}
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ lock_kernel(); /* Or else! */
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
@@ -298,13 +345,11 @@ 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);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void mem_address_unaligned(struct pt_regs *regs)
@@ -333,19 +378,16 @@ void do_privact(struct pt_regs *regs)
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(tstate & TSTATE_PRIV)
die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* XXX User may want to be allowed to do this. XXX */
@@ -353,7 +395,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long tstate)
{
- lock_kernel();
if(regs->tstate & TSTATE_PRIV) {
printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
regs->u_regs[UREG_RETPC]);
@@ -363,15 +404,12 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGBUS, current, 1);
- unlock_kernel();
}
void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- lock_kernel();
send_sig(SIGILL, current, 1);
- unlock_kernel();
}
/* Trap level 1 stuff or other traps we should never see... */
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 73bda96d9..bf00cb231 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
+/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,8 @@ tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq13: TRAP_IRQ(handler_irq, 13)
+tl0_itick: TRAP_TICK
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
@@ -99,6 +100,7 @@ tl0_bkpt: BREAKPOINT_TRAP
tl0_resv102: BTRAP(0x102)
tl0_flushw: FLUSH_WINDOW_TRAP
tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
+ .globl tl0_solaris
tl0_solaris: SOLARIS_SYSCALL_TRAP
tl0_netbsd: NETBSD_SYSCALL_TRAP
tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index f66889195..3aea13953 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.1 1997/07/18 06:26:45 ralf Exp $
+/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -205,19 +205,19 @@ __asm__ __volatile__ ( \
"stx %%g7, [%0 + 8]\n" \
"0:\n\n\t" \
".section __ex_table\n\t" \
- ".xword 4b, " #errh "\n\t" \
- ".xword 5b, " #errh "\n\t" \
- ".xword 6b, " #errh "\n\t" \
- ".xword 7b, " #errh "\n\t" \
- ".xword 8b, " #errh "\n\t" \
- ".xword 9b, " #errh "\n\t" \
- ".xword 10b, " #errh "\n\t" \
- ".xword 11b, " #errh "\n\t" \
- ".xword 12b, " #errh "\n\t" \
- ".xword 13b, " #errh "\n\t" \
- ".xword 14b, " #errh "\n\t" \
- ".xword 15b, " #errh "\n\t" \
- ".xword 16b, " #errh "\n\n\t" \
+ ".word 4b, " #errh "\n\t" \
+ ".word 5b, " #errh "\n\t" \
+ ".word 6b, " #errh "\n\t" \
+ ".word 7b, " #errh "\n\t" \
+ ".word 8b, " #errh "\n\t" \
+ ".word 9b, " #errh "\n\t" \
+ ".word 10b, " #errh "\n\t" \
+ ".word 11b, " #errh "\n\t" \
+ ".word 12b, " #errh "\n\t" \
+ ".word 13b, " #errh "\n\t" \
+ ".word 14b, " #errh "\n\t" \
+ ".word 15b, " #errh "\n\t" \
+ ".word 16b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), "r" (asi) \
: "l1", "l2", "g7", "g1", "cc"); \
@@ -259,20 +259,20 @@ __asm__ __volatile__ ( \
"17:\t" "stba %%l1, [%0 + 1] %%asi\n" \
"0:\n\n\t" \
".section __ex_table\n\t" \
- ".xword 4b, " #errh "\n\t" \
- ".xword 5b, " #errh "\n\t" \
- ".xword 6b, " #errh "\n\t" \
- ".xword 7b, " #errh "\n\t" \
- ".xword 8b, " #errh "\n\t" \
- ".xword 9b, " #errh "\n\t" \
- ".xword 10b, " #errh "\n\t" \
- ".xword 11b, " #errh "\n\t" \
- ".xword 12b, " #errh "\n\t" \
- ".xword 13b, " #errh "\n\t" \
- ".xword 14b, " #errh "\n\t" \
- ".xword 15b, " #errh "\n\t" \
- ".xword 16b, " #errh "\n\t" \
- ".xword 17b, " #errh "\n\n\t" \
+ ".word 4b, " #errh "\n\t" \
+ ".word 5b, " #errh "\n\t" \
+ ".word 6b, " #errh "\n\t" \
+ ".word 7b, " #errh "\n\t" \
+ ".word 8b, " #errh "\n\t" \
+ ".word 9b, " #errh "\n\t" \
+ ".word 10b, " #errh "\n\t" \
+ ".word 11b, " #errh "\n\t" \
+ ".word 12b, " #errh "\n\t" \
+ ".word 13b, " #errh "\n\t" \
+ ".word 14b, " #errh "\n\t" \
+ ".word 15b, " #errh "\n\t" \
+ ".word 16b, " #errh "\n\t" \
+ ".word 17b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi) \
: "l1", "l2", "g7", "g1", "cc"); \
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index f2c714eae..0ebf92767 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
+/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -143,8 +143,9 @@ spill_fixup:
retry
window_scheisse_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_scheisse_merge:
srlx %l5, PAGE_SHIFT, %o1
@@ -244,8 +245,9 @@ spill_fixup_mna:
retry
window_mna_from_user_common:
wrpr %g1, %cwp
+ sethi %hi(109f), %g7
ba,pt %xcc, etrap
- rd %pc, %g7
+109: or %g7, %lo(109b), %g7
window_mna_merge:
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 3da21c606..9f8729ee5 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,12 +1,12 @@
-# $Id: Makefile,v 1.13 1997/07/16 10:12:03 jj Exp $
+# $Id: Makefile,v 1.15 1997/08/19 03:11:50 davem Exp $
# Makefile for Sparc library files..
#
-CFLAGS := $(CFLAGS) -ansi
+CFLAGS := $(CFLAGS)
-OBJS = blockops.o locks.o strlen.o strncmp.o \
+OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
- VIScopy.o VISbzero.o VISmemset.o VIScsum.o
+ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c
new file mode 100644
index 000000000..6677f581a
--- /dev/null
+++ b/arch/sparc64/lib/PeeCeeI.c
@@ -0,0 +1,225 @@
+/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $
+ * PeeCeeI.c: The emerging standard...
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/io.h>
+
+void outsb(unsigned long addr, const void *src, unsigned long count)
+{
+ const u8 *p = src;
+
+ while(count--)
+ outb(*p++, addr);
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count)
+{
+ if(count) {
+ const u16 *ps = src;
+ const u32 *pi;
+
+ if(((u64)src) & 0x2) {
+ outw(*ps++, addr);
+ count--;
+ }
+ pi = (const u32 *)ps;
+ while(count >= 2) {
+ u32 w;
+
+ w = *pi++;
+ outw(w >> 16, addr);
+ outw(w, addr);
+ count -= 2;
+ }
+ ps = (const u16 *)pi;
+ if(count)
+ outw(*ps, addr);
+ }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count)
+{
+ if(count) {
+ if((((u64)src) & 0x3) == 0) {
+ const u32 *p = src;
+ while(count--)
+ outl(*p++, addr);
+ } else {
+ const u8 *pb;
+ const u16 *ps = src;
+ u32 l = 0, l2;
+ const u32 *pi;
+
+ switch(((u64)src) & 0x3) {
+ case 0x2:
+ count -= 1;
+ l = *ps++;
+ pi = (const u32 *)ps;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l <<16) | (l2 >> 16)), addr);
+ l = l2;
+ }
+ ps = (const u16 *)pi;
+ outl(((l << 16) | (*ps >> 16)), addr);
+ break;
+
+ case 0x1:
+ count -= 1;
+ pb = src;
+ l = (*pb++ << 16);
+ ps = (const u16 *)pb;
+ l |= *ps++;
+ pi = (const u32 *)ps;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l << 8) | (l2 >> 24)), addr);
+ l = l2;
+ }
+ pb = (const u8 *)pi;
+ outl(((l << 8) | (*pb >> 24)), addr);
+ break;
+
+ case 0x3:
+ count -= 1;
+ pb = src;
+ l = (*pb++ >> 24);
+ pi = (const u32 *)pb;
+ while(count--) {
+ l2 = *pi++;
+ outl(((l << 24) | (l2 >> 8)), addr);
+ l = l2;
+ }
+ ps = (const u16 *)pi;
+ l2 = (*ps++ << 16);
+ pb = (const u8 *)ps;
+ l2 |= (*pb << 8);
+ outl(((l << 24) | (l2 >> 8)), addr);
+ break;
+ }
+ }
+ }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ u32 *pi;
+ u8 *pb = dst;
+
+ while((((unsigned long)pb) & 0x3) && count--)
+ *pb++ = inb(addr);
+ pi = (u32 *)pb;
+ while(count >= 4) {
+ u32 w;
+
+ w = (inb(addr) << 24);
+ w |= (inb(addr) << 16);
+ w |= (inb(addr) << 8);
+ w |= inb(addr);
+ *pi++ = w;
+ count -= 4;
+ }
+ pb = (u8 *)pi;
+ while(count--)
+ *pb++ = inb(addr);
+ }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ u16 *ps = dst;
+ u32 *pi;
+
+ if(((unsigned long)ps) & 0x2) {
+ *ps++ = inw(addr);
+ count--;
+ }
+ pi = (u32 *)ps;
+ while(count >= 2) {
+ u32 w;
+
+ w = (inw(addr) << 16);
+ w |= inw(addr);
+ *pi++ = w;
+ count -= 2;
+ }
+ ps = (u16 *)pi;
+ if(count)
+ *ps = inw(addr);
+ }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count)
+{
+ if(count) {
+ if((((unsigned long)dst) & 0x3) == 0) {
+ u32 *pi = dst;
+ while(count--)
+ *pi++ = inl(addr);
+ } else {
+ u32 l = 0, l2, *pi;
+ u16 *ps;
+ u8 *pb;
+
+ switch(((unsigned long)dst) & 3) {
+ case 0x2:
+ ps = dst;
+ count -= 1;
+ l = inl(addr);
+ *ps++ = (l >> 16);
+ pi = (u32 *)ps;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = (l << 16) | (l2 >> 16);
+ l = l2;
+ }
+ ps = (u16 *)pi;
+ *ps = (l << 16);
+ break;
+
+ case 0x1:
+ pb = dst;
+ count -= 1;
+ *pb++ = (l >> 24);
+ ps = (u16 *)pb;
+ *ps++ = (l >> 8);
+ pi = (u32 *)ps;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = ((l << 24) | (l2 >> 8));
+ l = l2;
+ }
+ pb = (u8 *)pi;
+ *pb = (l >> 8);
+ break;
+
+ case 0x3:
+ pb = (u8 *)dst;
+ count -= 1;
+ l = inl(addr);
+ *pb++ = l >> 24;
+ pi = (u32 *)pb;
+ while(count--) {
+ l2 = inl(addr);
+ *pi++ = ((l >> 24) | (l2 << 8));
+ l = l2;
+ }
+ ps = (u16 *)pi;
+ *ps++ = l >> 8;
+ pb = (u8 *)ps;
+ *pb = l;
+ break;
+ }
+ }
+ }
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S
index 3c86861fd..ede87843b 100644
--- a/arch/sparc64/lib/VISbzero.S
+++ b/arch/sparc64/lib/VISbzero.S
@@ -1,4 +1,4 @@
-/* $Id: VISbzero.S,v 1.1 1997/07/18 06:26:48 ralf Exp $
+/* $Id: VISbzero.S,v 1.8 1997/08/22 15:54:50 jj Exp $
* VISbzero.S: High speed clear operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -16,8 +16,8 @@
99: ba VISbzerofixup_ret##z; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXC(x,y,a,b,c...) \
@@ -28,15 +28,15 @@
ba VISbzerofixup_ret0; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXO1(x,y) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VISbzerofixup_reto1; \
+ .align 4; \
+ .word 98b, VISbzerofixup_reto1; \
.text; \
.align 4;
#define EX(x,y,a,b) EXN(x,y,a,b,0)
@@ -44,8 +44,8 @@
#define EX2(x,y,a,b) EXN(x,y,a,b,2)
#define EXT(start,end,handler) \
.section __ex_table; \
- .align 8; \
- .xword start, 0, end, handler; \
+ .align 4; \
+ .word start, 0, end, handler; \
.text; \
.align 4
#else
@@ -147,7 +147,7 @@ bzero:
#else
wr %g0, ASI_BLK_P, %asi
#endif
- membar #StoreStore | #LoadStore
+ membar #StoreLoad | #StoreStore | #LoadStore
fzero %f0
andcc %o3, 0xc0, %o2
and %o1, 0x3f, %o1
@@ -180,16 +180,28 @@ bzero:
#ifdef __KERNEL__
wr %g0, 0, %fprs
wr %g7, 0x0, %asi
+#else
+#ifndef REGS_64BIT
+ wr %g0, FPRS_FEF, %fprs
#endif
- membar #Sync
+#endif
+ membar #StoreLoad | #StoreStore
9: andcc %o1, 0xf8, %o2
be,pn %xcc, 13f
andcc %o1, 7, %o1
+#ifdef __KERNEL__
+14: sethi %hi(13f), %o4
+ srl %o2, 1, %o3
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %o2, %o0
+#else
14: rd %pc, %o4
srl %o2, 1, %o3
sub %o4, %o3, %o4
jmpl %o4 + (13f - 14b), %g0
add %o0, %o2, %o0
+#endif
12: ZERO_BLOCKS(%o0, 0xc8, %g0)
ZERO_BLOCKS(%o0, 0x88, %g0)
ZERO_BLOCKS(%o0, 0x48, %g0)
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index 1429f1658..40b781e73 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.1 1997/07/18 06:26:48 ralf Exp $
+/* $Id: VIScopy.S,v 1.14 1997/08/22 15:54:53 jj Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -42,8 +42,8 @@
99: ba VIScopyfixup_ret; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EX2(x,y,c,d,e,a,b) \
@@ -54,37 +54,48 @@
ba VIScopyfixup_ret; \
a, b, %o0; \
.section __ex_table; \
- .align 8; \
- .xword 98b, 99b; \
+ .align 4; \
+ .word 98b, 99b; \
.text; \
.align 4;
#define EXO2(x,y) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VIScopyfixup_reto2; \
+ .align 4; \
+ .word 98b, VIScopyfixup_reto2; \
.text; \
.align 4;
#define EXVISN(x,y,n) \
98: x,y; \
.section __ex_table; \
- .align 8; \
- .xword 98b, VIScopyfixup_vis##n; \
+ .align 4; \
+ .word 98b, VIScopyfixup_vis##n; \
.text; \
.align 4;
#define EXT(start,end,handler) \
.section __ex_table; \
- .align 8; \
- .xword start, 0, end, handler; \
+ .align 4; \
+ .word start, 0, end, handler; \
.text; \
.align 4;
#else
-#define FPU_CLEAN_RETL \
- retl; \
+#ifdef REGS_64BIT
+#define FPU_CLEAN_RETL \
+ retl; \
mov %g6, %o0;
-#define FPU_RETL \
- retl; \
+#define FPU_RETL \
+ retl; \
mov %g6, %o0;
+#else
+#define FPU_CLEAN_RETL \
+ wr %g0, FPRS_FEF, %fprs; \
+ retl; \
+ mov %g6, %o0;
+#define FPU_RETL \
+ wr %g0, FPRS_FEF, %fprs; \
+ retl; \
+ mov %g6, %o0;
+#endif
#define NORMAL_RETL \
retl; \
mov %g6, %o0;
@@ -113,8 +124,8 @@
#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \
EXVIS(LDBLK [%src] ASIBLK, %fdest); \
- add %src, 0x40, %src; \
ASI_SETDST_BLK \
+ add %src, 0x40, %src; \
add %dest, 0x40, %dest; \
subcc %len, 0x40, %len; \
be,pn %xcc, jmptgt; \
@@ -303,7 +314,7 @@ copy_page: wr %g0, FPRS_FEF, %fprs ! FPU Group
sethi %hi(8192), %o2 ! IEU0 Group
mov ASI_BLK_P, asi_src ! IEU1
b,pt %xcc, dest_is_64byte_aligned ! CTI
- mov ASI_BLK_COMMIT_P, asi_dest ! IEU0 Group
+ mov ASI_BLK_P, asi_dest ! IEU0 Group
.align 32
.globl __copy_from_user
@@ -446,6 +457,13 @@ dest_is_64byte_aligned:
EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group
sub %g7, 0x80, %g7 ! IEU0
EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group
+#ifdef __KERNEL__
+vispc: sll %g2, 9, %g2 ! IEU0 Group
+ sethi %hi(vis00), %g5 ! IEU1
+ or %g5, %lo(vis00), %g5 ! IEU0 Group
+ jmpl %g5 + %g2, %g0 ! CTI Group brk forced
+ addcc %o1, 0xc0, %o1 ! IEU1 Group
+#else
! Clk1 Group 8-(
! Clk2 Group 8-(
! Clk3 Group 8-(
@@ -455,6 +473,7 @@ vispc: rd %pc, %g5 ! PDU Group 8-(
sll %g2, 9, %g2 ! IEU0
jmpl %g5 + %g2, %g0 ! CTI Group brk forced
addcc %o1, 0xc0, %o1 ! IEU1 Group
+#endif
.align 512 /* OK, here comes the fun part... */
vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01)
FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02)
@@ -721,20 +740,21 @@ __memcpy_16plus:
3: andcc %o2, 0x70, %g7 ! IEU1 Group
41: be,pn %xcc, 80f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
- ! Clk1 8-(
- ! Clk2 8-(
- ! Clk3 8-(
- ! Clk4 8-(
-79: rd %pc, %o5 ! PDU Group
#ifdef __KERNEL__
+79: sethi %hi(80f), %o5 ! IEU0
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
srl %g7, 1, %g2 ! IEU0 Group
sub %o5, %g5, %o5 ! IEU1
sub %o5, %g2, %o5 ! IEU0 Group
- jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced
+ jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced
add %o0, %g7, %o0 ! IEU0 Group
#else
+ ! Clk1 8-(
+ ! Clk2 8-(
+ ! Clk3 8-(
+ ! Clk4 8-(
+79: rd %pc, %o5 ! PDU Group
sll %g7, 1, %g5 ! IEU0 Group
add %o1, %g7, %o1 ! IEU1
sub %o5, %g5, %o5 ! IEU0 Group
@@ -814,19 +834,20 @@ normal_retl:
andcc %o2, 0x70, %g7 ! IEU1
be,pn %xcc, 84f ! CTI
andcc %o2, 8, %g0 ! IEU1 Group
+#ifdef __KERNEL__
+83: srl %g7, 1, %g5 ! IEU0
+ sethi %hi(84f), %o5 ! IEU0 Group
+ add %g7, %g5, %g5 ! IEU1
+ add %o1, %g7, %o1 ! IEU0 Group
+ sub %o5, %g5, %o5 ! IEU1
+ jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced
+ add %o0, %g7, %o0 ! IEU0 Group
+#else
! Clk1 8-(
! Clk2 8-(
! Clk3 8-(
! Clk4 8-(
83: rd %pc, %o5 ! PDU Group
-#ifdef __KERNEL__
- srl %g7, 1, %g5 ! IEU0 Group
- add %g7, %g5, %g5 ! IEU0 Group
- add %o1, %g7, %o1 ! IEU1
- sub %o5, %g5, %o5 ! IEU0 Group
- jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
- add %o0, %g7, %o0 ! IEU0 Group
-#else
add %o1, %g7, %o1 ! IEU0 Group
sub %o5, %g7, %o5 ! IEU1
jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
index 1ccb98759..81b020c49 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ b/arch/sparc64/lib/VIScsum.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsum.S,v 1.1 1997/07/18 06:26:49 ralf Exp $
+/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
* VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -345,11 +345,19 @@ csum_partial:
20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
be,pn %icc, 23f /* CTI */
and %o1, 0xf, %o3 /* IEU0 */
-22: rd %pc, %g7 /* LSU Group */
+#ifdef __KERNEL__
+22: sll %g1, 1, %o4 /* IEU0 Group */
+ sethi %hi(23f), %g7 /* IEU1 */
+ sub %g7, %o4, %g7 /* IEU0 Group */
+ jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */
+ add %o0, %g1, %o0 /* IEU0 */
+#else
+22: rd %pc, %g7 /* LSU Group+4bubbles */
sll %g1, 1, %o4 /* IEU0 Group */
sub %g7, %o4, %g7 /* IEU0 Group (regdep) */
jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */
- add %o0, %g1, %o0 /* IEU0 */
+ add %o0, %g1, %o0 /* IEU0 */
+#endif
CSUM_LASTCHUNK(0xe0)
CSUM_LASTCHUNK(0xd0)
CSUM_LASTCHUNK(0xc0)
diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
new file mode 100644
index 000000000..efd2bfcd5
--- /dev/null
+++ b/arch/sparc64/lib/VIScsumcopy.S
@@ -0,0 +1,880 @@
+/* $Id: VIScsumcopy.S,v 1.2 1997/08/19 15:25:22 jj Exp $
+ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
+ * copying utilizing the UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996,1997 David S. Miller
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF 0x7ff+128
+#else
+#define STACKOFF 64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#else
+#define ASI_P 0x80
+#define ASI_BLK_P 0xf0
+#define FRPS_FEF 0x04
+#define FPRS_DU 0x02
+#define FPRS_DL 0x01
+#endif
+#define ASI_BLK_XOR (ASI_BLK_P ^ ASI_P)
+
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+#define x1 g1
+#define x2 g2
+#define x3 g3
+#define x4 g4
+#define x5 g5
+#define x6 g7
+#define x7 o4
+#define x8 o5
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ * Once AGAIN, the SunSoft engineers are caught
+ * asleep at the keyboard :)).
+ * The main loop does about 20 superscalar cycles
+ * per 64bytes checksummed/copied.
+ */
+
+#define LDBLK(O0) \
+ ldda [%src] %asi, %O0 /* Load Group */
+
+#define STBLK \
+ stda %f48, [%dst] ASI_BLK_P /* Store */
+
+#define ST(fx,off) \
+ std %fx, [%dst + off] /* Store */
+
+#define SYNC \
+ membar #Sync
+
+
+#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
+ LOAD /* Load Group */; \
+ faligndata %A14, %F0, %A14 /* FPA Group */; \
+ inc %x5 /* IEU0 */; \
+ STORE1 /* Store (optional) */; \
+ faligndata %F0, %F2, %A0 /* FPA Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA Group */; \
+ inc %x6 /* IEU0 */; \
+ STORE2 /* Store (optional) */; \
+ faligndata %F2, %F4, %A2 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA Group */; \
+ add %src, 64, %src /* IEU0 */; \
+ add %dst, 64, %dst /* IEU1 */; \
+ fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \
+ inc %x7 /* IEU0 */; \
+ STORE3 /* Store (optional) */; \
+ faligndata %F4, %F6, %A4 /* FPA */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %F4, %f4, %F4 /* FPA */; \
+ fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \
+ inc %x8 /* IEU0 */; \
+ STORE4 /* Store (optional) */; \
+ faligndata %F6, %F8, %A6 /* FPA */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fpadd32 %F6, %f6, %F6 /* FPA */; \
+ fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \
+ inc %x1 /* IEU0 */; \
+ STORE5 /* Store (optional) */; \
+ faligndata %F8, %F10, %A8 /* FPA */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %F8, %f8, %F8 /* FPA */; \
+ fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \
+ inc %x2 /* IEU0 */; \
+ STORE6 /* Store (optional) */; \
+ faligndata %F10, %F12, %A10 /* FPA */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fpadd32 %F10, %f10, %F10 /* FPA */; \
+ fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \
+ inc %x3 /* IEU0 */; \
+ STORE7 /* Store (optional) */; \
+ faligndata %F12, %F14, %A12 /* FPA */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ fpadd32 %F12, %f12, %F12 /* FPA */; \
+ fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \
+ inc %x4 /* IEU0 */; \
+ STORE8 /* Store (optional) */; \
+ fmovd %F14, %B14 /* FPA */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fpadd32 %F14, %f14, %F14 /* FPA */; \
+ fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \
+ subcc %len, 64, %len /* IEU1 */; \
+ BRANCH /* CTI */; \
+ fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \
+
+#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
+ inc %x5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA */; \
+ fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fpadd32 %f14, %f12, %S3 /* FPA */; \
+ inc %x8 /* IEU0 Group */; \
+ add %sum, %x7, %sum /* IEU1 */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ fpadd32 %S2, %S3, %T1 /* FPA */; \
+ inc %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ add %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA */; \
+ fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ inc %x7 /* IEU1 */; \
+ fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \
+ ba,pt %xcc, ett /* CTI */; \
+ fmovd %FA, %FB /* FPA */; \
+
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
+ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
+
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
+ fpadd32 %U0, %U1, %V0 /* FPA Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ std %V0, [%sp + STACKOFF] /* Store Group */; \
+ inc %x8 /* IEU0 */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ inc %x1 /* IEU1 */; \
+ fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ sub %sum, %x8, %sum /* IEU1 */; \
+ ldx [%sp + STACKOFF], %x8 /* Load Group */; \
+ inc %x2 /* IEU0 */; \
+ sub %sum, %x1, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ inc %x3 /* IEU1 */; \
+ fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ sub %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ sub %sum, %x3, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ inc %x5 /* IEU1 */; \
+ fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ sub %sum, %x4, %sum /* IEU1 */; \
+ fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \
+ inc %x6 /* IEU0 */; \
+ sub %sum, %x5, %sum /* IEU1 */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ inc %x7 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ inc %x1 /* IEU0 Group */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ sub %sum, %x2, %sum /* IEU0 Group */; \
+ addcc %sum, %x8, %sum /* IEU Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %sum, 1, %sum /* IEU0 */; \
+33: /* That's it */;
+
+ .text
+ .globl csum_partial_copy_vis
+ .align 32
+/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */
+/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+csum_partial_copy_vis:
+ andcc %dst, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ and %dst, 0x38, %g3 /* IEU0 */
+ mov 1, %g5 /* IEU0 Group */
+ andcc %dst, 2, %g0 /* IEU1 */
+ be,pt %icc, 1f /* CTI */
+ and %dst, 4, %g7 /* IEU0 Group */
+ lduha [%src] %asi, %g2 /* Load */
+ sub %len, 2, %len /* IEU0 Group */
+ add %dst, 2, %dst /* IEU1 */
+ andcc %dst, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sth %g2, [%dst - 2] /* Store Group */
+ sll %g2, 16, %g2 /* IEU0 */
+ add %src, 2, %src /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, %g5, %sum /* IEU0 */
+1: lduwa [%src] %asi, %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %dst, 0x38, %g3 /* IEU0 */
+ add %dst, 4, %dst /* IEU0 Group */
+ sub %len, 4, %len /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: and %dst, 0x38, %g3 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ add %src, 4, %src /* IEU1 */
+4:
+#ifdef __KERNEL__
+ wr %g0, FPRS_FEF, %fprs /* LSU Group */
+#endif
+ mov %src, %g7 /* IEU1 Group */
+ fzero %f48 /* FPA */
+ alignaddr %src, %g0, %src /* Single Group */
+ subcc %g7, %src, %g7 /* IEU1 Group */
+ be,pt %xcc, 1f /* CTI */
+ mov 0x40, %g1 /* IEU0 */
+ lduwa [%src] %asi, %g2 /* Load Group */
+ subcc %sum, %g2, %sum /* IEU1 Group+load stall */
+ bcs,a,pn %icc, 1f /* CTI */
+ sub %sum, 1, %sum /* IEU0 */
+1: srl %sum, 0, %sum /* IEU0 Group */
+ clr %g5 /* IEU1 */
+ brz,pn %g3, 3f /* CTI+IEU1 Group */
+ sub %g1, %g3, %g1 /* IEU0 */
+ ldda [%src] %asi, %f0 /* Load */
+ clr %g3 /* IEU0 Group */
+ andcc %dst, 8, %g0 /* IEU1 */
+ be,pn %icc, 1f /* CTI */
+ ldda [%src + 8] %asi, %f2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ sub %len, 8, %len /* IEU1 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ addcc %dst, 8, %dst /* IEU1 Group */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g3 /* FPM Group */
+ fmovd %f2, %f0 /* FPA Group */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ std %f16, [%dst - 8] /* Store */
+ fmovd %f50, %f48 /* FPA */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ add %src, 16, %src /* IEU0 */
+ add %dst, 16, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ sub %len, 16, %len /* IEU0 */
+ inc %g3 /* IEU1 */
+ std %f16, [%dst - 16] /* Store Group */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ srl %g3, 1, %o5 /* IEU0 */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ std %f18, [%dst - 8] /* Store */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ fmovd %f4, %f0 /* FPA */
+1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
+ rd %asi, %g2 /* LSU Group + 4 bubbles */
+ inc %g5 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ add %dst, 32, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o5 /* FPM Group */
+ inc %g3 /* IEU0 */
+ ldda [%src + 24] %asi, %f6 /* Load */
+ srl %g3, 1, %g3 /* IEU0 Group */
+ add %g5, %sum, %sum /* IEU1 */
+ ldda [%src + 32] %asi, %f8 /* Load */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ sub %len, 32, %len /* IEU0 */
+ std %f16, [%dst - 32] /* Store */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ inc %o5 /* IEU0 */
+ add %g3, %sum, %sum /* IEU1 */
+ fpadd32 %f4, %f48, %f50 /* FPA */
+ faligndata %f4, %f6, %f20 /* FPA Group */
+ srl %o5, 1, %o5 /* IEU0 */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ std %f18, [%dst - 24] /* Store */
+ fpadd32 %f6, %f50, %f48 /* FPA */
+ inc %o4 /* IEU0 Group */
+ std %f20, [%dst - 16] /* Store */
+ add %src, 32, %src /* IEU1 */
+ faligndata %f6, %f8, %f22 /* FPA */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ srl %o4, 1, %o4 /* IEU0 */
+ std %f22, [%dst - 8] /* Store */
+ add %o4, %sum, %sum /* IEU0 Group */
+3: rd %asi, %g2 /* LSU Group + 4 bubbles */
+#ifdef __KERNEL__
+4: sethi %hi(vis0s), %g7 /* IEU0 Group */
+#else
+4: rd %pc, %g7 /* LSU Group + 4 bubbles */
+#endif
+ inc %g5 /* IEU0 Group */
+ and %src, 0x38, %o4 /* IEU1 */
+ membar #StoreLoad /* LSU Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ inc %g3 /* IEU1 */
+ sll %o4, 8, %o4 /* IEU0 Group */
+ sub %len, 0xc0, %len /* IEU1 */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ srl %g3, 1, %g3 /* IEU0 */
+ add %g7, %o4, %g7 /* IEU0 Group */
+ add %g3, %sum, %sum /* IEU1 */
+#ifdef __KERNEL__
+ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
+#else
+ jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
+#endif
+ fzero %f32 /* FPA */
+
+ .align 2048
+vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f62 /* FPA Group */
+ faligndata %f0, %f2, %f48 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x1 /* FPM Group */
+ fpadd32 %f0, %f62, %f0 /* FPA */
+ fcmpgt32 %f32, %f4, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f50 /* FPA */
+ fcmpgt32 %f62, %f0, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f52 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ inc %x1 /* IEU0 */
+ faligndata %f6, %f8, %f54 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ srl %x1, 1, %x1 /* IEU0 */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f56 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ add %sum, %x1, %sum /* IEU1 */
+ faligndata %f10, %f12, %f58 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f60 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f62 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f32), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f0), STBLK,,,,,,,,
+ ,bcs,pn %icc, vis0e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f16), STBLK,,,,,,,,
+ ,bcc,pt %icc, vis0)
+vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f32,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
+vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f0,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
+vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f16,
+ ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+ ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 8, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f48 /* FPA */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f50 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f52 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f54 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ faligndata %f10, %f12, %f56 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f58 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f60 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f32), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f0), ,STBLK,,,,,,,
+ ,bcs,pn %icc, vis1e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+ ,LDBLK(f16), ,STBLK,,,,,,,
+ ,bcc,pt %icc, vis1)
+vis1e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f32,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
+vis1e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f0,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
+vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f62,f48,f50,f52,f54,f56,f58,f60,f16,
+ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+ ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 16, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f48 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f50 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f52 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f54 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ faligndata %f12, %f14, %f56 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f58 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
+vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f32), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f0), ,,STBLK,,,,,,
+ ,bcs,pn %icc, vis2e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+ ,LDBLK(f16), ,,STBLK,,,,,,
+ ,bcc,pt %icc, vis2)
+vis2e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f32,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
+vis2e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f0,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
+vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f60,f62,f48,f50,f52,f54,f56,f58,f16,
+ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+ ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 24, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f48 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f50 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f52 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f54 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f56 /* FPA */
+ inc %x4 /* IEU0 */
+ srl %x4, 1, %x4 /* IEU0 Group */
+vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f32), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f0), ,,,STBLK,,,,,
+ ,bcs,pn %icc, vis3e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+ ,LDBLK(f16), ,,,STBLK,,,,,
+ ,bcc,pt %icc, vis3)
+vis3e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f32,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
+vis3e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f0,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
+vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f58,f60,f62,f48,f50,f52,f54,f56,f16,
+ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+ ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 32, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fzero %f2 /* FPA Group */
+ fzero %f4 /* FPA Group */
+ fzero %f6 /* FPA Group */
+ clr %x4 /* IEU0 */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f48 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f50 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f52 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f54 /* FPA */
+vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f32), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f0), ,,,,STBLK,,,,
+ ,bcs,pn %icc, vis4e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+ ,LDBLK(f16), ,,,,STBLK,,,,
+ ,bcc,pt %icc, vis4)
+vis4e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f32,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
+vis4e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f0,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
+vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f56,f58,f60,f62,f48,f50,f52,f54,f16,
+ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+ ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis5s: add %src, 128 - 40, %src /* IEU0 Group */
+ ldda [%src-88] %asi, %f10 /* Load Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f10, %f12, %f48 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f50 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f52 /* FPA */
+vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f32), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f0), ,,,,,STBLK,,,
+ ,bcs,pn %icc, vis5e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+ ,LDBLK(f16), ,,,,,STBLK,,,
+ ,bcc,pt %icc, vis5)
+vis5e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f32,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
+vis5e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f0,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
+vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f54,f56,f58,f60,f62,f48,f50,f52,f16,
+ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
+ ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis6s: add %src, 128 - 48, %src /* IEU0 Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f12, %f14, %f48 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f50 /* FPA */
+vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f32), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f0), ,,,,,,STBLK,,
+ ,bcs,pn %icc, vis6e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+ ,LDBLK(f16), ,,,,,,STBLK,,
+ ,bcc,pt %icc, vis6)
+vis6e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f32,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
+vis6e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f0,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
+vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f52,f54,f56,f58,f60,f62,f48,f50,f16,
+ ,SYNC, ,,,,,,STBLK,ST(f48,64),
+ ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
+ .align 2048
+vis7s: add %src, 128 - 56, %src /* IEU0 Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ faddd %f32, %f32, %f12 /* FPA Group */
+ clr %x7 /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fmovd %f14, %f48 /* FPA */
+vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f32), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e1)
+ DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f0), ,,,,,,,STBLK,
+ ,bcs,pn %icc, vis7e2)
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+ ,LDBLK(f16), ,,,,,,,STBLK,
+ ,bcc,pt %icc, vis7)
+vis7e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f32,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
+vis7e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f0,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
+vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ ,f50,f52,f54,f56,f58,f60,f62,f48,f16,
+ ,SYNC, ,,,,,,,STBLK,
+ ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
+e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
+e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
+e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
+ett: rd %gsr, %x3 /* LSU Group+4bubbles */
+ andcc %x3, 7, %x3 /* IEU1 Group */
+ add %dst, 8, %dst /* IEU0 Group */
+ bne,pn %icc, 1f /* CTI */
+ fzero %f10 /* FPA */
+ brz,a,pn %len, 2f /* CTI+IEU1 Group */
+ std %f6, [%dst - 8] /* Store */
+1: rd %asi, %x4 /* LSU Group+4bubbles */
+ sub %src, 64, %src /* IEU0 Group */
+ cmp %len, 8 /* IEU1 */
+ blu,pn %icc, 3f /* CTI */
+ wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */
+1: ldda [%src] %asi, %f2 /* Load Group */
+ fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ faligndata %f6, %f2, %f14 /* FPA Group */
+ fcmpgt32 %f10, %f12, %x5 /* FPM Group */
+ std %f14, [%dst - 16] /* Store */
+ fmovd %f2, %f6 /* FPA */
+ fmovd %f12, %f10 /* FPA Group */
+ sub %len, 8, %len /* IEU1 */
+ fzero %f16 /* FPA Group - FPU nop */
+ fzero %f18 /* FPA Group - FPU nop */
+ inc %x5 /* IEU0 */
+ srl %x5, 1, %x5 /* IEU0 Group (regdep) */
+ cmp %len, 8 /* IEU1 */
+ bgeu,pt %icc, 1b /* CTI */
+ add %x5, %sum, %sum /* IEU0 Group */
+3: brz,a,pt %x3, 2f /* CTI+IEU1 */
+ std %f6, [%dst - 8] /* Store Group */
+ st %f7, [%dst - 8] /* Store Group */
+ sub %dst, 4, %dst /* IEU0 */
+ add %len, 4, %len /* IEU1 */
+2:
+#ifdef __KERNEL__
+ sub %sp, 8, %sp /* IEU0 Group */
+#endif
+ END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
+ membar #Sync /* LSU Group */
+#ifdef __KERNEL__
+ wr %g0, 0, %fprs /* LSU Group */
+ add %sp, 8, %sp /* IEU0 Group */
+#endif
+23: brnz,pn %len, 26f /* CTI+IEU1 Group */
+24: sllx %sum, 32, %g1 /* IEU0 */
+25: addcc %sum, %g1, %src /* IEU1 Group */
+ srlx %src, 32, %src /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %src, 1, %src /* IEU1 */
+#ifndef __KERNEL__
+1: retl /* CTI Group brk forced */
+ srl %src, 0, %src /* IEU0 */
+#else
+1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
+ retl /* CTI Group brk forced */
+ sllx %g4, 32, %g4 /* IEU0 */
+#endif
+26: andcc %len, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ lduwa [%src] %asi, %g3 /* Load */
+ lduwa [%src+4] %asi, %g2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ sllx %g3, 32, %g5 /* IEU0 Group */
+ stw %g3, [%dst - 8] /* Store */
+ or %g5, %g2, %g5 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: andcc %len, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduwa [%src] %asi, %g7 /* Load */
+ add %src, 4, %src /* IEU0 Group */
+ add %dst, 4, %dst /* IEU1 */
+ sllx %g7, 32, %g2 /* IEU0 Group */
+ stw %g7, [%dst - 4] /* Store */
+1: andcc %len, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduha [%src] %asi, %g7 /* Load */
+ add %src, 2, %src /* IEU1 */
+ add %dst, 2, %dst /* IEU0 Group */
+ sll %g7, 16, %o4 /* IEU0 Group */
+ sth %g7, [%dst - 2] /* Store */
+1: andcc %len, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ lduba [%src] %asi, %g7 /* Load */
+ sll %g7, 8, %o5 /* IEU0 Group */
+ stb %g7, [%dst] /* Store */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %sum, %sum /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %sum, 32, %g1 /* IEU0 */
+
+#ifdef __KERNEL__
+end:
+
+ .section __ex_table
+ .align 4
+ .word csum_partial_copy_vis, 0, end, cpc_handler
+#endif
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
index d674f2a6e..4c24931ba 100644
--- a/arch/sparc64/lib/VISmemset.S
+++ b/arch/sparc64/lib/VISmemset.S
@@ -1,4 +1,4 @@
-/* $Id: VISmemset.S,v 1.1 1997/07/18 06:26:49 ralf Exp $
+/* $Id: VISmemset.S,v 1.7 1997/08/22 15:54:56 jj Exp $
* VISmemset.S: High speed memset operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -171,11 +171,22 @@ memset:
12:
#ifdef __KERNEL__
wr %g0, 0, %fprs
+#else
+#ifndef REGS_64BIT
+ wr %g0, FPRS_FEF, %fprs
#endif
- membar #Sync
+#endif
+ membar #StoreLoad | #StoreStore
9: andcc %o2, 0x78, %g5
be,pn %xcc, 13f
andcc %o2, 7, %o2
+#ifdef __KERNEL__
+14: srl %g5, 1, %o3
+ sethi %hi(13f), %o4
+ sub %o4, %o3, %o4
+ jmpl %o4 + %lo(13f), %g0
+ add %o0, %g5, %o0
+#else
14: rd %pc, %o4
#ifdef REGS_64BIT
srl %g5, 1, %o3
@@ -185,6 +196,7 @@ memset:
#endif
jmpl %o4 + (13f - 14b), %g0
add %o0, %g5, %o0
+#endif
12: SET_BLOCKS(%o0, 0x68, %o1)
SET_BLOCKS(%o0, 0x48, %o1)
SET_BLOCKS(%o0, 0x28, %o1)
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index 59083aa02..7d5b240ad 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
+/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,7 +15,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */
wr %g0, FPRS_FEF, %fprs ! FPU Group
ldd [%o1], %f48 ! Load Group
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
mov 32, %g2 ! IEU0 Group
/* Cannot perform real arithmatic on the pattern, that can
@@ -36,7 +36,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */
subcc %g2, 1, %g2 ! IEU1 Group
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
@@ -56,7 +56,7 @@ __bzero_1page:
faddd %f0, %f2, %f12 ! FPA Group
fmuld %f0, %f2, %f14 ! FPM
wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreStore | #LoadStore ! LSU Group
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
1: stda %f0, [%o0 + 0x00] %asi ! Store Group
stda %f0, [%o0 + 0x40] %asi ! Store Group
stda %f0, [%o0 + 0x80] %asi ! Store Group
@@ -65,6 +65,6 @@ __bzero_1page:
subcc %g1, 1, %g1 ! IEU1
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0 Group
- membar #Sync ! LSU Group
+ membar #StoreLoad | #StoreStore ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
wr %g0, 0, %fprs ! FPU Group
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 703370fc6..5f35f136b 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -23,456 +23,456 @@
* are two fold. Firstly, they cannot pair with jack shit,
* and also they only add in the 32-bit carry condition bit
* into the accumulated sum. The following is much better.
- *
- * This should run at max bandwidth for ecache hits, a better
- * technique is to use VIS and fpu operations. This is already
- * done for csum_partial, needs to be written for the copy stuff
- * still.
+ * For larger chunks we use VIS code, which is faster ;)
*/
- .text
- .globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+ .text
/* I think I have an erection... Once _AGAIN_ the SunSoft
* engineers are caught asleep at the keyboard, tsk tsk...
*/
-#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7) \
- ldxa [src + off + 0x00] %asi, t0; \
- ldxa [src + off + 0x08] %asi, t1; \
- ldxa [src + off + 0x10] %asi, t2; \
- ldxa [src + off + 0x18] %asi, t3; \
- ldxa [src + off + 0x20] %asi, t4; \
- ldxa [src + off + 0x28] %asi, t5; \
- ldxa [src + off + 0x30] %asi, t6; \
- ldxa [src + off + 0x38] %asi, t7; \
+#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ ldxa [%src + off + 0x38] %asi, t7; \
nop; nop; /* DO NOT TOUCH THIS!!!!! */
-#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stx t0, [dest + off - 0x40]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stx t0, [%dst + off - 0x40]; \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 11f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-11: stx t1, [dest + off - 0x38]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+11: stx t1, [%dst + off - 0x38]; \
+ addcc %sum, t1, %sum; \
bcc,pt %xcc, 12f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-12: stx t2, [dest + off - 0x30]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+12: stx t2, [%dst + off - 0x30]; \
+ addcc %sum, t2, %sum; \
bcc,pt %xcc, 13f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-13: stx t3, [dest + off - 0x28]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+13: stx t3, [%dst + off - 0x28]; \
+ addcc %sum, t3, %sum; \
bcc,pt %xcc, 14f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-14: stx t4, [dest + off - 0x20]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+14: stx t4, [%dst + off - 0x20]; \
+ addcc %sum, t4, %sum; \
bcc,pt %xcc, 15f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-15: stx t5, [dest + off - 0x18]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+15: stx t5, [%dst + off - 0x18]; \
+ addcc %sum, t5, %sum; \
bcc,pt %xcc, 16f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-16: stx t6, [dest + off - 0x10]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+16: stx t6, [%dst + off - 0x10]; \
+ addcc %sum, t6, %sum; \
bcc,pt %xcc, 17f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-17: stx t7, [dest + off - 0x08]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+17: stx t7, [%dst + off - 0x08]; \
+ addcc %sum, t7, %sum; \
bcc,pt %xcc, 18f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
18:
-#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
- stw t0, [dest + off - 0x3c]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off - 0x3c]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
- stw t0, [dest + off - 0x40]; \
+ stw t0, [%dst + off - 0x40]; \
bcc,pt %xcc, 21f; \
- ldxa [src + off + 0x00] %asi, t0; \
- add sum, 1, sum; \
-21: stw t1, [dest + off - 0x34]; \
- addcc sum, t1, sum; \
+ ldxa [%src + off + 0x00] %asi, t0; \
+ add %sum, 1, %sum; \
+21: stw t1, [%dst + off - 0x34]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
- stw t1, [dest + off - 0x38]; \
+ stw t1, [%dst + off - 0x38]; \
bcc,pt %xcc, 22f; \
- ldxa [src + off + 0x08] %asi, t1; \
- add sum, 1, sum; \
-22: stw t2, [dest + off - 0x2c]; \
- addcc sum, t2, sum; \
+ ldxa [%src + off + 0x08] %asi, t1; \
+ add %sum, 1, %sum; \
+22: stw t2, [%dst + off - 0x2c]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
- stw t2, [dest + off - 0x30]; \
+ stw t2, [%dst + off - 0x30]; \
bcc,pt %xcc, 23f; \
- ldxa [src + off + 0x10] %asi, t2; \
- add sum, 1, sum; \
-23: stw t3, [dest + off - 0x24]; \
- addcc sum, t3, sum; \
+ ldxa [%src + off + 0x10] %asi, t2; \
+ add %sum, 1, %sum; \
+23: stw t3, [%dst + off - 0x24]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
- stw t3, [dest + off - 0x28]; \
+ stw t3, [%dst + off - 0x28]; \
bcc,pt %xcc, 24f; \
- ldxa [src + off + 0x18] %asi, t3; \
- add sum, 1, sum; \
-24: stw t4, [dest + off - 0x1c]; \
- addcc sum, t4, sum; \
+ ldxa [%src + off + 0x18] %asi, t3; \
+ add %sum, 1, %sum; \
+24: stw t4, [%dst + off - 0x1c]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
- stw t4, [dest + off - 0x20]; \
+ stw t4, [%dst + off - 0x20]; \
bcc,pt %xcc, 25f; \
- ldxa [src + off + 0x20] %asi, t4; \
- add sum, 1, sum; \
-25: stw t5, [dest + off - 0x14]; \
- addcc sum, t5, sum; \
+ ldxa [%src + off + 0x20] %asi, t4; \
+ add %sum, 1, %sum; \
+25: stw t5, [%dst + off - 0x14]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
- stw t5, [dest + off - 0x18]; \
+ stw t5, [%dst + off - 0x18]; \
bcc,pt %xcc, 26f; \
- ldxa [src + off + 0x28] %asi, t5; \
- add sum, 1, sum; \
-26: stw t6, [dest + off - 0x0c]; \
- addcc sum, t6, sum; \
+ ldxa [%src + off + 0x28] %asi, t5; \
+ add %sum, 1, %sum; \
+26: stw t6, [%dst + off - 0x0c]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
- stw t6, [dest + off - 0x10]; \
+ stw t6, [%dst + off - 0x10]; \
bcc,pt %xcc, 27f; \
- ldxa [src + off + 0x30] %asi, t6; \
- add sum, 1, sum; \
-27: stw t7, [dest + off - 0x04]; \
- addcc sum, t7, sum; \
+ ldxa [%src + off + 0x30] %asi, t6; \
+ add %sum, 1, %sum; \
+27: stw t7, [%dst + off - 0x04]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
- stw t7, [dest + off - 0x08]; \
+ stw t7, [%dst + off - 0x08]; \
bcc,pt %xcc, 28f; \
- ldxa [src + off + 0x38] %asi, t7; \
- add sum, 1, sum; \
+ ldxa [%src + off + 0x38] %asi, t7; \
+ add %sum, 1, %sum; \
28:
-#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ addcc %sum, t0, %sum; \
bcc,pt %xcc, 31f; \
- stx t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-31: addcc sum, t1, sum; \
+ stx t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+31: addcc %sum, t1, %sum; \
bcc,pt %xcc, 32f; \
- stx t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-32: addcc sum, t2, sum; \
+ stx t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+32: addcc %sum, t2, %sum; \
bcc,pt %xcc, 33f; \
- stx t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-33: addcc sum, t3, sum; \
+ stx t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+33: addcc %sum, t3, %sum; \
bcc,pt %xcc, 34f; \
- stx t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-34: addcc sum, t4, sum; \
+ stx t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+34: addcc %sum, t4, %sum; \
bcc,pt %xcc, 35f; \
- stx t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-35: addcc sum, t5, sum; \
+ stx t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+35: addcc %sum, t5, %sum; \
bcc,pt %xcc, 36f; \
- stx t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-36: addcc sum, t6, sum; \
+ stx t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+36: addcc %sum, t6, %sum; \
bcc,pt %xcc, 37f; \
- stx t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-37: addcc sum, t7, sum; \
+ stx t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+37: addcc %sum, t7, %sum; \
bcc,pt %xcc, 38f; \
- stx t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stx t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
38:
-#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \
- stw t0, [dest + off + 0x04]; \
- addcc sum, t0, sum; \
+#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ stw t0, [%dst + off + 0x04]; \
+ addcc %sum, t0, %sum; \
srlx t0, 32, t0; \
bcc,pt %xcc, 41f; \
- stw t0, [dest + off + 0x00]; \
- add sum, 1, sum; \
-41: stw t1, [dest + off + 0x0c]; \
- addcc sum, t1, sum; \
+ stw t0, [%dst + off + 0x00]; \
+ add %sum, 1, %sum; \
+41: stw t1, [%dst + off + 0x0c]; \
+ addcc %sum, t1, %sum; \
srlx t1, 32, t1; \
bcc,pt %xcc, 42f; \
- stw t1, [dest + off + 0x08]; \
- add sum, 1, sum; \
-42: stw t2, [dest + off + 0x14]; \
- addcc sum, t2, sum; \
+ stw t1, [%dst + off + 0x08]; \
+ add %sum, 1, %sum; \
+42: stw t2, [%dst + off + 0x14]; \
+ addcc %sum, t2, %sum; \
srlx t2, 32, t2; \
bcc,pt %xcc, 43f; \
- stw t2, [dest + off + 0x10]; \
- add sum, 1, sum; \
-43: stw t3, [dest + off + 0x1c]; \
- addcc sum, t3, sum; \
+ stw t2, [%dst + off + 0x10]; \
+ add %sum, 1, %sum; \
+43: stw t3, [%dst + off + 0x1c]; \
+ addcc %sum, t3, %sum; \
srlx t3, 32, t3; \
bcc,pt %xcc, 44f; \
- stw t3, [dest + off + 0x18]; \
- add sum, 1, sum; \
-44: stw t4, [dest + off + 0x24]; \
- addcc sum, t4, sum; \
+ stw t3, [%dst + off + 0x18]; \
+ add %sum, 1, %sum; \
+44: stw t4, [%dst + off + 0x24]; \
+ addcc %sum, t4, %sum; \
srlx t4, 32, t4; \
bcc,pt %xcc, 45f; \
- stw t4, [dest + off + 0x20]; \
- add sum, 1, sum; \
-45: stw t5, [dest + off + 0x2c]; \
- addcc sum, t5, sum; \
+ stw t4, [%dst + off + 0x20]; \
+ add %sum, 1, %sum; \
+45: stw t5, [%dst + off + 0x2c]; \
+ addcc %sum, t5, %sum; \
srlx t5, 32, t5; \
bcc,pt %xcc, 46f; \
- stw t5, [dest + off + 0x28]; \
- add sum, 1, sum; \
-46: stw t6, [dest + off + 0x34]; \
- addcc sum, t6, sum; \
+ stw t5, [%dst + off + 0x28]; \
+ add %sum, 1, %sum; \
+46: stw t6, [%dst + off + 0x34]; \
+ addcc %sum, t6, %sum; \
srlx t6, 32, t6; \
bcc,pt %xcc, 47f; \
- stw t6, [dest + off + 0x30]; \
- add sum, 1, sum; \
-47: stw t7, [dest + off + 0x3c]; \
- addcc sum, t7, sum; \
+ stw t6, [%dst + off + 0x30]; \
+ add %sum, 1, %sum; \
+47: stw t7, [%dst + off + 0x3c]; \
+ addcc %sum, t7, %sum; \
srlx t7, 32, t7; \
bcc,pt %xcc, 48f; \
- stw t7, [dest + off + 0x38]; \
- add sum, 1, sum; \
+ stw t7, [%dst + off + 0x38]; \
+ add %sum, 1, %sum; \
48:
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1) \
- ldxa [src - off - 0x08] %asi, t0; \
- ldxa [src - off - 0x00] %asi, t1; \
+#define CSUMCOPY_LASTCHUNK(off, t0, t1) \
+ ldxa [%src - off - 0x08] %asi, t0; \
+ ldxa [%src - off - 0x00] %asi, t1; \
nop; nop; \
- addcc t0, sum, sum; \
- stw t0, [dst - off - 0x04]; \
+ addcc t0, %sum, %sum; \
+ stw t0, [%dst - off - 0x04]; \
srlx t0, 32, t0; \
bcc,pt %xcc, 51f; \
- stw t0, [dst - off - 0x08]; \
- add sum, 1, sum; \
-51: addcc t1, sum, sum; \
- stw t1, [dst - off + 0x04]; \
+ stw t0, [%dst - off - 0x08]; \
+ add %sum, 1, %sum; \
+51: addcc t1, %sum, %sum; \
+ stw t1, [%dst - off + 0x04]; \
srlx t1, 32, t1; \
bcc,pt %xcc, 52f; \
- stw t1, [dst - off - 0x00]; \
- add sum, 1, sum; \
+ stw t1, [%dst - off - 0x00]; \
+ add %sum, 1, %sum; \
52:
+cpc_start:
cc_end_cruft:
- andcc %o3, 8, %g0 ! IEU1 Group
+ andcc %g7, 8, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- and %o3, 4, %g5 ! IEU0
- ldxa [%o0 + 0x00] %asi, %g2 ! Load Group
- add %o1, 8, %o1 ! IEU0
- add %o0, 8, %o0 ! IEU1
- addcc %g2, %g7, %g7 ! IEU1 Group + 2 bubbles
- stw %g2, [%o1 - 0x04] ! Store
+ and %g7, 4, %g5 ! IEU0
+ ldxa [%src + 0x00] %asi, %g2 ! Load Group
+ add %dst, 8, %dst ! IEU0
+ add %src, 8, %src ! IEU1
+ addcc %g2, %sum, %sum ! IEU1 Group + 2 bubbles
+ stw %g2, [%dst - 0x04] ! Store
srlx %g2, 32, %g2 ! IEU0
bcc,pt %xcc, 1f ! CTI Group
- stw %g2, [%o1 - 0x08] ! Store
- add %g7, 1, %g7 ! IEU0
+ stw %g2, [%dst - 0x08] ! Store
+ add %sum, 1, %sum ! IEU0
1: brz,pt %g5, 1f ! CTI Group
clr %g2 ! IEU0
- lduwa [%o0 + 0x00] %asi, %g2 ! Load
- add %o1, 4, %o1 ! IEU0 Group
- add %o0, 4, %o0 ! IEU1
- stw %g2, [%o1 - 0x04] ! Store Group + 2 bubbles
+ lduwa [%src + 0x00] %asi, %g2 ! Load
+ add %dst, 4, %dst ! IEU0 Group
+ add %src, 4, %src ! IEU1
+ stw %g2, [%dst - 0x04] ! Store Group + 2 bubbles
sllx %g2, 32, %g2 ! IEU0
-1: andcc %o3, 2, %g0 ! IEU1
+1: andcc %g7, 2, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o4 ! IEU1
- lduha [%o0 + 0x00] %asi, %o4 ! Load
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
- sth %o4, [%o1 - 0x2] ! Store Group + 2 bubbles
+ lduha [%src + 0x00] %asi, %o4 ! Load
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
+ sth %o4, [%dst - 0x2] ! Store Group + 2 bubbles
sll %o4, 16, %o4 ! IEU0
-1: andcc %o3, 1, %g0 ! IEU1
+1: andcc %g7, 1, %g0 ! IEU1
be,pn %icc, 1f ! CTI Group
clr %o5 ! IEU0
- lduba [%o0 + 0x00] %asi, %o5 ! Load
- stb %o5, [%o1 + 0x00] ! Store Group + 2 bubbles
+ lduba [%src + 0x00] %asi, %o5 ! Load
+ stb %o5, [%dst + 0x00] ! Store Group + 2 bubbles
sll %o5, 8, %o5 ! IEU0
1: or %g2, %o4, %o4 ! IEU1
or %o5, %o4, %o4 ! IEU0 Group
- addcc %o4, %g7, %g7 ! IEU1
+ addcc %o4, %sum, %sum ! IEU1
bcc,pt %xcc, ccfold ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 Group
b,pt %xcc, ccfold ! CTI
- add %g7, 1, %g7 ! IEU1
+ add %sum, 1, %sum ! IEU1
cc_fixit:
bl,a,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- andcc %o0, 1, %g0 ! IEU1 Group
- bne,pn %icc, ccslow ! CTI
- andcc %o0, 2, %g0 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ andcc %src, 2, %g0 ! IEU1 Group
be,pn %icc, 1f ! CTI
- andcc %o0, 0x4, %g0 ! IEU1 Group
- lduha [%o0 + 0x00] %asi, %g4 ! Load
- sub %g1, 2, %g1 ! IEU0
- add %o0, 2, %o0 ! IEU0 Group
- add %o1, 2, %o1 ! IEU1
+ andcc %src, 0x4, %g0 ! IEU1 Group
+ lduha [%src + 0x00] %asi, %g4 ! Load
+ sub %len, 2, %len ! IEU0
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
sll %g4, 16, %g3 ! IEU0 Group + 1 bubble
- addcc %g3, %g7, %g7 ! IEU1
+ addcc %g3, %sum, %sum ! IEU1
bcc,pt %xcc, 0f ! CTI
- srl %g7, 16, %g3 ! IEU0 Group
+ srl %sum, 16, %g3 ! IEU0 Group
add %g3, 1, %g3 ! IEU0 4 clocks (mispredict)
-0: andcc %o0, 0x4, %g0 ! IEU1 Group
- sth %g4, [%o1 - 0x2] ! Store
- sll %g7, 16, %g7 ! IEU0
+0: andcc %src, 0x4, %g0 ! IEU1 Group
+ sth %g4, [%dst - 0x2] ! Store
+ sll %sum, 16, %sum ! IEU0
sll %g3, 16, %g3 ! IEU0 Group
- srl %g7, 16, %g7 ! IEU0 Group
- or %g3, %g7, %g7 ! IEU0 Group (regdep)
+ srl %sum, 16, %sum ! IEU0 Group
+ or %g3, %sum, %sum ! IEU0 Group (regdep)
1: be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU1
- lduwa [%o0 + 0x00] %asi, %g4 ! Load Group
- sub %g1, 4, %g1 ! IEU0
- add %o0, 4, %o0 ! IEU1
- add %o1, 4, %o1 ! IEU0 Group
- addcc %g4, %g7, %g7 ! IEU1 Group + 1 bubble
- stw %g4, [%o1 - 0x4] ! Store
+ andn %len, 0xff, %g2 ! IEU1
+ lduwa [%src + 0x00] %asi, %g4 ! Load Group
+ sub %len, 4, %len ! IEU0
+ add %src, 4, %src ! IEU1
+ add %dst, 4, %dst ! IEU0 Group
+ addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble
+ stw %g4, [%dst - 0x4] ! Store
bcc,pt %xcc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0 Group
+ andn %len, 0xff, %g2 ! IEU0 Group
b,pt %xcc, cc_dword_aligned ! CTI 4 clocks (mispredict)
- add %g7, 1, %g7 ! IEU0
+ add %sum, 1, %sum ! IEU0
.align 32
- .globl __csum_partial_copy_sparc_generic, csum_partial_copy
-csum_partial_copy:
-__csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */
- xorcc %o0, %o1, %o4 ! IEU1 Group
- srl %g7, 0, %g7 ! IEU0
+ .globl csum_partial_copy_sparc64
+csum_partial_copy_sparc64: /* %o0=src, %o1=dest, %o2=len, %o3=sum */
+ xorcc %src, %dst, %o4 ! IEU1 Group
+ srl %sum, 0, %sum ! IEU0
andcc %o4, 3, %g0 ! IEU1 Group
- srl %g1, 0, %g1 ! IEU0
+ srl %len, 0, %len ! IEU0
+ bne,pn %icc, ccslow ! CTI
+ andcc %src, 1, %g0 ! IEU1 Group
bne,pn %icc, ccslow ! CTI
- andcc %o0, 7, %g0 ! IEU1 Group
+ cmp %len, 256 ! IEU1 Group
+ bgeu,pt %icc, csum_partial_copy_vis ! CTI
+ andcc %src, 7, %g0 ! IEU1 Group
be,pt %icc, cc_dword_aligned ! CTI
- andn %g1, 0xff, %g2 ! IEU0
+ andn %len, 0xff, %g2 ! IEU0
b,pt %xcc, cc_fixit ! CTI Group
- cmp %g1, 6 ! IEU1
+ cmp %len, 6 ! IEU1
cc_dword_aligned:
brz,pn %g2, 3f ! CTI Group
- andcc %o1, 4, %g0 ! IEU1 Group (brz uses IEU1)
+ andcc %dst, 4, %g0 ! IEU1 Group (brz uses IEU1)
be,pn %icc, ccdbl + 4 ! CTI
-5: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STUNALIGN( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+5: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STUNALIGN( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
10:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, 5b ! CTI
- add %o1, 256, %o1 ! IEU0
-3: andcc %g1, 0xf0, %o2 ! IEU1 Group
+ add %dst, 256, %dst ! IEU0
+3: andcc %len, 0xf0, %g1 ! IEU1 Group
ccmerge:be,pn %icc, ccte ! CTI
- andcc %g1, 0xf, %o3 ! IEU1 Group
- sll %o2, 2, %o4 ! IEU0
-13: rd %pc, %o5 ! LSU Group + 4 clocks
- add %o0, %o2, %o0 ! IEU0 Group
- sub %o5, %o4, %o5 ! IEU1 Group
- jmpl %o5 + (12f - 13b), %g0 ! CTI Group brk forced
- add %o1, %o2, %o1 ! IEU0 Group
-cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3)
- CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3)
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ sll %g1, 2, %o4 ! IEU0
+13: sethi %hi(12f), %o5 ! IEU0 Group
+ add %src, %g1, %src ! IEU1
+ sub %o5, %o4, %o5 ! IEU0 Group
+ jmpl %o5 + %lo(12f), %g0 ! CTI Group brk forced
+ add %dst, %g1, %dst ! IEU0 Group
+cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
12:
- andcc %g1, 0xf, %o3 ! IEU1 Group
+ andcc %len, 0xf, %g7 ! IEU1 Group
ccte: bne,pn %icc, cc_end_cruft ! CTI
sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
-ccfold: sllx %g7, 32, %o0 ! IEU0 Group
- addcc %g7, %o0, %o0 ! IEU1 Group (regdep)
+ccfold: sllx %sum, 32, %o0 ! IEU0 Group
+ addcc %sum, %o0, %o0 ! IEU1 Group (regdep)
srlx %o0, 32, %o0 ! IEU0 Group (regdep)
bcs,a,pn %xcc, 1f ! CTI
add %o0, 1, %o0 ! IEU1 4 clocks (mispredict)
1: retl ! CTI Group brk forced
sllx %g4, 32,%g4 ! IEU0 Group
-ccdbl: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
- CSUMCOPY_EC_STALIGNED( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ccdbl: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+ CSUMCOPY_EC_STALIGNED( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
11:
- sub %g1, 256, %g1 ! IEU0 Group
- add %o0, 256, %o0 ! IEU1
- andncc %g1, 0xff, %g0 ! IEU1 Group
+ sub %len, 256, %len ! IEU0 Group
+ add %src, 256, %src ! IEU1
+ andncc %len, 0xff, %g0 ! IEU1 Group
bne,pt %icc, ccdbl ! CTI
- add %o1, 256, %o1 ! IEU0
+ add %dst, 256, %dst ! IEU0
b,pt %xcc, ccmerge ! CTI Group
- andcc %g1, 0xf0, %o2 ! IEU1
+ andcc %len, 0xf0, %g1 ! IEU1
ccslow: mov 0, %g5
- brlez,pn %g1, 4f
- andcc %o0, 1, %o5
+ brlez,pn %len, 4f
+ andcc %src, 1, %o5
be,a,pt %icc, 1f
- srl %g1, 1, %o3
- sub %g1, 1, %g1
- lduba [%o0] %asi, %g5
- add %o0, 1, %o0
- stb %g5, [%o1]
- srl %g1, 1, %o3
- add %o1, 1, %o1
-1: brz,a,pn %o3, 3f
- andcc %g1, 1, %g0
- andcc %o0, 2, %g0
+ srl %len, 1, %g7
+ sub %len, 1, %len
+ lduba [%src] %asi, %g5
+ add %src, 1, %src
+ stb %g5, [%dst]
+ srl %len, 1, %g7
+ add %dst, 1, %dst
+1: brz,a,pn %g7, 3f
+ andcc %len, 1, %g0
+ andcc %src, 2, %g0
be,a,pt %icc, 1f
- srl %o3, 1, %o3
- lduha [%o0] %asi, %o4
- sub %g1, 2, %g1
+ srl %g7, 1, %g7
+ lduha [%src] %asi, %o4
+ sub %len, 2, %len
srl %o4, 8, %g2
- sub %o3, 1, %o3
- stb %g2, [%o1]
+ sub %g7, 1, %g7
+ stb %g2, [%dst]
add %o4, %g5, %g5
- stb %o4, [%o1 + 1]
- add %o0, 2, %o0
- srl %o3, 1, %o3
- add %o1, 2, %o1
-1: brz,a,pn %o3, 2f
- andcc %g1, 2, %g0
- lda [%o0] %asi, %o4
+ stb %o4, [%dst + 1]
+ add %src, 2, %src
+ srl %g7, 1, %g7
+ add %dst, 2, %dst
+1: brz,a,pn %g7, 2f
+ andcc %len, 2, %g0
+ lduwa [%src] %asi, %o4
5: srl %o4, 24, %g2
srl %o4, 16, %g3
- stb %g2, [%o1]
+ stb %g2, [%dst]
srl %o4, 8, %g2
- stb %g3, [%o1 + 1]
- add %o0, 4, %o0
- stb %g2, [%o1 + 2]
+ stb %g3, [%dst + 1]
+ add %src, 4, %src
+ stb %g2, [%dst + 2]
addcc %o4, %g5, %g5
- stb %o4, [%o1 + 3]
- addc %g5, %g0, %g5 ! I am now to lazy to optimize this (question is if it
- add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl
- subcc %o3, 1, %o3 ! tricks
+ stb %o4, [%dst + 3]
+ addc %g5, %g0, %g5
+ add %dst, 4, %dst
+ subcc %g7, 1, %g7
bne,a,pt %icc, 5b
- lda [%o0] %asi, %o4
+ lduwa [%src] %asi, %o4
sll %g5, 16, %g2
srl %g5, 16, %g5
srl %g2, 16, %g2
- andcc %g1, 2, %g0
+ andcc %len, 2, %g0
add %g2, %g5, %g5
2: be,a,pt %icc, 3f
- andcc %g1, 1, %g0
- lduha [%o0] %asi, %o4
- andcc %g1, 1, %g0
+ andcc %len, 1, %g0
+ lduha [%src] %asi, %o4
+ andcc %len, 1, %g0
srl %o4, 8, %g2
- add %o0, 2, %o0
- stb %g2, [%o1]
+ add %src, 2, %src
+ stb %g2, [%dst]
add %g5, %o4, %g5
- stb %o4, [%o1 + 1]
- add %o1, 2, %o1
+ stb %o4, [%dst + 1]
+ add %dst, 2, %dst
3: be,a,pt %icc, 1f
sll %g5, 16, %o4
- lduba [%o0] %asi, %g2
+ lduba [%src] %asi, %g2
sll %g2, 8, %o4
- stb %g2, [%o1]
+ stb %g2, [%dst]
add %g5, %o4, %g5
sll %g5, 16, %o4
1: addcc %o4, %g5, %g5
@@ -484,8 +484,22 @@ ccslow: mov 0, %g5
and %o4, 0xff, %o4
sll %g2, 8, %g2
or %g2, %o4, %g5
-4: addcc %g7, %g5, %g7
- addc %g0, %g7, %o0
+4: addcc %sum, %g5, %sum
+ addc %g0, %sum, %o0
retl
srl %o0, 0, %o0
-__csum_partial_copy_end:
+cpc_end:
+
+ .globl cpc_handler
+cpc_handler:
+ ldx [%sp + 0x7ff + 128], %g1
+ sub %g0, EFAULT, %g2
+ brnz,a,pt %g1, 1f
+ st %g2, [%g1]
+1: retl
+ nop
+
+ .section __ex_table
+ .align 4
+ .word cpc_start, 0, cpc_end, cpc_handler
+
diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S
index 74054f63a..7b2bdba62 100644
--- a/arch/sparc64/lib/locks.S
+++ b/arch/sparc64/lib/locks.S
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
+/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
* locks.S: SMP low-level lock primitives on Sparc64.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -12,9 +12,9 @@
.align 32
___lk_busy_spin:
- orcc %g2, 0, %g0
- bne,pt %icc, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+ ldub [%g1 + 0], %g2
+ brnz,pt %g2, ___lk_busy_spin
+ membar #LoadLoad
b,pt %xcc, 1f
ldstub [%g1 + 0], %g2
@@ -23,16 +23,15 @@ ___lock_kernel:
addcc %g2, -1, %g2
rdpr %pil, %g3
bcs,a,pn %icc, 9f
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g0, 15, %pil
ldstub [%g1 + 0], %g2
-1: brnz,a,pn %g2, ___lk_busy_spin
- ldub [%g1 + 0], %g2
+1: brnz,pn %g2, ___lk_busy_spin
+ membar #StoreLoad | #StoreStore
lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
2: mov -1, %g2
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
wrpr %g3, 0, %pil
9: jmpl %o7 + 0x8, %g0
mov %g5, %o7
@@ -41,16 +40,16 @@ ___lock_kernel:
___lock_reacquire_kernel:
rdpr %pil, %g3
wrpr %g0, 15, %pil
- st %g2, [%g6 + AOFF_task_lock_depth]
+ stw %g2, [%g6 + AOFF_task_lock_depth]
ldstub [%g1 + 0], %g2
1: brz,pt %g2, 3f
- ldub [%g1 + 0], %g2
-2: brnz,a,pt %g2, 2b
- ldub [%g1 + 0], %g2
+ membar #StoreLoad | #StoreStore
+2: ldub [%g1 + 0], %g2
+ brnz,pt %g2, 2b
+ membar #LoadLoad
b,pt %xcc, 1b
ldstub [%g1 + 0], %g2
3: lduw [%g6 + AOFF_task_processor], %g2
- membar #LoadLoad | #LoadStore
stb %g2, [%g1 + 1]
wrpr %g3, 0, %pil
jmpl %o7 + 0x8, %g0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index ef6cee5a6..9ae3d0381 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -78,11 +78,11 @@ __strlen_user:
clr %o0
.section __ex_table,#alloc
- .align 8
+ .align 4
- .xword 10b, 30b
- .xword 11b, 30b
- .xword 12b, 30b
- .xword 15b, 30b
- .xword 13b, 30b
- .xword 14b, 30b
+ .word 10b, 30b
+ .word 11b, 30b
+ .word 12b, 30b
+ .word 15b, 30b
+ .word 13b, 30b
+ .word 14b, 30b
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index 7a5dc768f..e0fb0f09b 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -49,6 +49,6 @@ __strncpy_from_user:
mov -EFAULT, %o0
.section __ex_table,#alloc
- .align 8
- .xword 10b, 4b
- .xword 11b, 4b
+ .align 4
+ .word 10b, 4b
+ .word 11b, 4b
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 5e16e1218..6bc52f3eb 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.18 1997/07/17 02:20:56 davem Exp $
+/* $Id: fault.c,v 1.20 1997/08/04 16:16:51 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)
@@ -217,56 +217,3 @@ bad_area:
out:
unlock_kernel();
}
-
-void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
- struct vm_area_struct *vmaring;
- struct inode *inode;
- unsigned long vaddr, offset, start;
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
- int alias_found = 0;
-
- inode = vma->vm_dentry->d_inode;
- if(!inode)
- return;
-
- offset = (address & PAGE_MASK) - vma->vm_start;
- vmaring = inode->i_mmap;
- do {
- vaddr = vmaring->vm_start + offset;
-
- /* This conditional is misleading... */
- if((vaddr ^ address) & PAGE_SIZE) {
- alias_found++;
- start = vmaring->vm_start;
- while(start < vmaring->vm_end) {
- pgdp = pgd_offset(vmaring->vm_mm, start);
- if(!pgdp) goto next;
- pmdp = pmd_offset(pgdp, start);
- if(!pmdp) goto next;
- ptep = pte_offset(pmdp, start);
- if(!ptep) goto next;
-
- if(pte_val(*ptep) & _PAGE_PRESENT) {
- flush_cache_page(vmaring, start);
- *ptep = __pte(pte_val(*ptep) &
- ~(_PAGE_CV));
- flush_tlb_page(vmaring, start);
- }
- next:
- start += PAGE_SIZE;
- }
- }
- } while((vmaring = vmaring->vm_next_share) != NULL);
-
- if(alias_found && (pte_val(pte) & _PAGE_CV)) {
- pgdp = pgd_offset(vma->vm_mm, address);
- pmdp = pmd_offset(pgdp, address);
- ptep = pte_offset(pmdp, address);
- flush_cache_page(vma, address);
- *ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV));
- flush_tlb_page(vma, address);
- }
-}
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 386c8540f..4a7a1bce1 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
+/* $Id: init.c,v 1.55 1997/08/24 01:22:29 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,18 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION;
/* References to section boundaries */
extern char __init_begin, __init_end, etext, __bss_start;
+extern void __bfill64(void *, unsigned long *);
+
+static __inline__ void __init_pmd(pmd_t *pmdp)
+{
+ __bfill64((void *)pmdp, &null_pte_table);
+}
+
+static __inline__ void __init_pgd(pgd_t *pgdp)
+{
+ __bfill64((void *)pgdp, &null_pmd_table);
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
@@ -103,48 +115,72 @@ void show_mem(void)
/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
-/* XXX Also, play with the streaming buffers at some point, both
- * XXX Fusion and Sunfire both have them aparently... -DaveM
- */
-
/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
static unsigned long dvma_pages_current_offset = 0;
static int dvma_pages_current_index = 0;
+/* #define E3000_DEBUG */
+
__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
unsigned long memory_end, struct linux_sbus *sbus))
{
struct iommu_struct *iommu;
struct sysio_regs *sregs;
- struct linux_prom_registers rprop[2];
+ struct linux_prom64_registers rprop;
unsigned long impl, vers;
unsigned long control, tsbbase;
unsigned long *iopte;
+ u32 rlow, rhigh;
int err, i;
- err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+#ifdef E3000_DEBUG
+ prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
+ iommu_node, memory_start, memory_end, sbus);
+#endif
+ err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
sizeof(rprop));
if(err == -1) {
prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
- sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
- (void *)0,
+ rlow = (rprop.phys_addr & 0xffffffff);
+ rhigh = (rprop.phys_addr >> 32);
+#ifdef E3000_DEBUG
+ prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
+#endif
+ sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
sizeof(struct sysio_regs),
- "SYSIO Regs",
- rprop[0].which_io, 0x0);
+ "SYSIO Regs", rhigh, 0x0);
+#ifdef E3000_DEBUG
+ prom_printf("sregs[%p]\n");
+#endif
+ if(!sregs) {
+ prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
+ prom_halt();
+ }
memory_start = (memory_start + 7) & ~7;
iommu = (struct iommu_struct *) memory_start;
memory_start += sizeof(struct iommu_struct);
+
+#ifdef E3000_DEBUG
+ prom_printf("iommu_init: iommu[%p] ", iommu);
+#endif
+
+ spin_lock_init(&iommu->iommu_lock);
iommu->sysio_regs = sregs;
sbus->iommu = iommu;
control = sregs->iommu_control;
impl = (control & IOMMU_CTRL_IMPL) >> 60;
vers = (control & IOMMU_CTRL_VERS) >> 56;
- printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+#ifdef E3000_DEBUG
+ prom_printf("sreg_control[%08x]\n", control);
+ prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+ (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+#endif
+ printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
(unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
control &= ~(IOMMU_CTRL_TSBSZ);
@@ -168,7 +204,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
/* Setup aliased mappings... */
for(i = 0; i < (65536 - 4096); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
+ IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
iopte++;
}
@@ -177,15 +214,47 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
for( ; i < 65536; i++)
*iopte++ = 0;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
+#endif
sregs->iommu_tsbbase = __pa(tsbbase);
sregs->iommu_control = control;
+#ifdef E3000_DEBUG
+ prom_printf("done\n");
+#endif
+ /* Get the streaming buffer going. */
+ control = sregs->sbuf_control;
+ impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
+ vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
+#ifdef E3000_DEBUG
+ prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
+ control);
+#endif
+ printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+ (unsigned int)impl, (unsigned int)vers);
+ printk("FlushFLAG[%p,%016lx] ... ",
+ (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
+ (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+ *(iommu->sbuf_flushflag_va) = 0;
+ memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
+
+ sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+
+#ifdef E3000_DEBUG
+ prom_printf("done, returning %016lx\n", memory_start);
+#endif
+ printk("ENABLED\n");
+
+ /* Finally enable DVMA arbitration for all devices, just in case. */
+ sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
return memory_start;
}
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
+ struct linux_sbus *sbus)
{
- struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
@@ -193,6 +262,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
/* Find out if we need to grab some pages. */
if(!dvma_map_pages[dvma_pages_current_index] ||
((dvma_pages_current_offset + len) > (1 << 16))) {
+ struct linux_sbus *sbus;
unsigned long *iopte;
unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
int i;
@@ -212,9 +282,16 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
/* Stick it in the IOMMU. */
i = (65536 - 4096) + i;
- iopte = (unsigned long *)(iommu->page_table + i);
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= __pa(newpages);
+ for_each_sbus(sbus) {
+ struct iommu_struct *iommu = sbus->iommu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+ iopte = (unsigned long *)(iommu->page_table + i);
+ *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= __pa(newpages);
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+ }
}
/* Get this out of the way. */
@@ -258,6 +335,33 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
return (__u32)0;
}
+void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long start = (unsigned long) vaddr;
+ unsigned long end = PAGE_ALIGN(start + len);
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ start &= PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
{
while(sz >= 0) {
@@ -273,6 +377,36 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
}
}
+void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long flags;
+ unsigned int *sync_word;
+
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ while(sz >= 0) {
+ unsigned long start = sg[sz].dvma_addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+ start &= PAGE_MASK;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sz--;
+ }
+ sync_word = iommu->sbuf_flushflag_va;
+ sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+ membar("#StoreLoad | #MemIssue");
+ while((*sync_word & 0x1) == 0)
+ membar("#LoadLoad");
+ *sync_word = 0;
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
static char sfmmuinfo[512];
char *mmu_info(void)
@@ -340,7 +474,7 @@ int prom_itlb_ent, prom_dtlb_ent;
unsigned long prom_itlb_tag, prom_itlb_data;
unsigned long prom_dtlb_tag, prom_dtlb_data;
-static inline void inherit_locked_prom_mappings(void)
+void inherit_locked_prom_mappings(int save_p)
{
int i;
int dtlb_seen = 0;
@@ -367,9 +501,12 @@ static inline void inherit_locked_prom_mappings(void)
data = spitfire_get_dtlb_data(i);
if(!dtlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_dtlb_tag(i);
- prom_dtlb_ent = i;
- prom_dtlb_tag = tag;
- prom_dtlb_data = data;
+
+ if(save_p) {
+ prom_dtlb_ent = i;
+ prom_dtlb_tag = tag;
+ prom_dtlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
membar("#Sync");
@@ -390,9 +527,12 @@ static inline void inherit_locked_prom_mappings(void)
data = spitfire_get_itlb_data(i);
if(!itlb_seen && (data & _PAGE_L)) {
unsigned long tag = spitfire_get_itlb_tag(i);
- prom_itlb_ent = i;
- prom_itlb_tag = tag;
- prom_itlb_data = data;
+
+ if(save_p) {
+ prom_itlb_ent = i;
+ prom_itlb_tag = tag;
+ prom_itlb_data = data;
+ }
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
membar("#Sync");
@@ -443,10 +583,14 @@ void __flush_cache_all(void)
/* If not locked, zap it. */
void __flush_tlb_all(void)
{
- unsigned long flags;
+ unsigned long pstate;
int i;
- save_flags(flags); cli();
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate\n\t"
+ "flushw"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
for(i = 0; i < 64; i++) {
if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -465,19 +609,67 @@ void __flush_tlb_all(void)
membar("#Sync");
}
}
- restore_flags(flags);
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (pstate));
}
-void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx)
+/* We are always protected by scheduler_lock under SMP. */
+void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
{
- if((ctx & ~(CTX_VERSION_MASK)) == 0) {
- flush_tlb_all();
- ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
- if(ctx == 1)
- ctx = CTX_FIRST_VERSION;
+ unsigned int new_ctx = *ctx;
+
+ if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
+ new_ctx += CTX_FIRST_VERSION;
+ if(new_ctx == 1)
+ new_ctx = CTX_FIRST_VERSION;
+ *ctx = new_ctx;
+ DO_LOCAL_FLUSH(smp_processor_id());
}
- tlb_context_cache = ctx + 1;
- mm->context = ctx;
+ mm->context = new_ctx;
+ mm->cpu_vm_mask = 0; /* Callers sets it properly. */
+ (*ctx)++;
+}
+
+#ifndef __SMP__
+unsigned long *pgd_quicklist = NULL;
+unsigned long *pmd_quicklist = NULL;
+unsigned long *pte_quicklist = NULL;
+unsigned long pgtable_cache_size = 0;
+#endif
+
+pgd_t *get_pgd_slow(void)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+ if(pgd)
+ __init_pgd(pgd);
+ return pgd;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+ pmd_t *pmd;
+
+ pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+ if(pmd) {
+ __init_pmd(pmd);
+ pgd_set(pgd, pmd);
+ return pmd + offset;
+ }
+ return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) get_free_page(GFP_KERNEL);
+ if(pte) {
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ return NULL;
}
__initfunc(static void
@@ -595,7 +787,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
*/
pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
- save_flags(flags); cli();
+ __save_and_cli(flags);
__asm__ __volatile__("
stxa %1, [%0] %3
stxa %2, [%5] %4
@@ -608,15 +800,18 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
: "memory");
- restore_flags(flags);
+ __restore_flags(flags);
/* Now set kernel pgd to upper alias so physical page computations
* work.
*/
init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
- null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift);
- null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift);
+ /* The funny offsets are to make page table operations much quicker and
+ * requite less state, see pgtable.h for gory details.
+ */
+ null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
+ null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
pmdp = (pmd_t *) &empty_null_pmd_table;
for(i = 0; i < 1024; i++)
@@ -658,7 +853,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
flushi((long)&empty_zero_page);
membar("#Sync");
- inherit_locked_prom_mappings();
+ inherit_locked_prom_mappings(1);
flush_tlb_all();
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 18f9a363d..ec96e8871 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
+/* $Id: ultra.S,v 1.3 1997/08/30 04:53:20 ralf Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,28 +13,26 @@
.align 32
.globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
__flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
-9: mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
- ldxa [%g7] ASI_DMMU, %g2
+ mov SECONDARY_CONTEXT, %g7
+9: ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
- be,pt %icc, 1f
+ bne,pn %icc, 1f
mov 0x50, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
-
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
+ nop
__flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
sethi %hi(8192 - 1), %g5
or %g5, %lo(8192 - 1), %g5
@@ -43,19 +41,13 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
sub %o2, %o1, %o3
add %g5, 1, %g5
- orcc %o1, 0x50, %o1
+ orcc %o1, 0x10, %o1
srlx %o3, 13, %o4
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
-
- clr %g2
-1: cmp %o4, 96
+ cmp %o4, 96
bgu,pn %icc, 9b
- rdpr %pil, %g1
- mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
+ mov SECONDARY_CONTEXT, %g7
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
@@ -66,37 +58,37 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP
brnz,pt %o3, 1b
sub %o3, %g5, %o3
- nop
+ flush %g6
- be,pt %icc, 1f
- wrpr %g1, 0x0, %pil
+ be,a,pt %icc, 1f
+ nop
stxa %g2, [%g7] ASI_DMMU
-1: retl
- flush %g6
+1: flush %g6
+ wrpr %g1, 0, %pstate
+ retl
+ nop
.align 32
__flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
- rdpr %otherwin, %g1
- brz,pt %g1, 1f
- mov %o7, %g3
- call __flushw_user
- clr %g2
-1: rdpr %pil, %g1
mov SECONDARY_CONTEXT, %g7
- wrpr %g0, 15, %pil
-
ldxa [%g7] ASI_DMMU, %g2
cmp %g2, %o0
be,pt %icc, 1f
or %o1, 0x10, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+1: rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%g7] ASI_DMMU
-1: stxa %g0, [%g3] ASI_DMMU_DEMAP
- be,pt %icc, 1f
- stxa %g0, [%g3] ASI_IMMU_DEMAP
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
stxa %g2, [%g7] ASI_DMMU
-1: wrpr %g1, 0x0, %pil
+ flush %g6
retl
- flush %g6
+ wrpr %g1, 0, %pstate
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
@@ -111,50 +103,29 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
* %g2 scratch 1
* %g3 scratch 2
* %g4 scratch 3
- *
- * NOTE: We do not acknowledge the UPA until we are done
- * with the service. This is what tells the master
- * that he can consider the effects of the flush
- * "complete" on this cpu.
*/
.align 32
- .globl xcall_flush_tlb_page
+ .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
xcall_flush_tlb_page:
mov SECONDARY_CONTEXT, %g2
- nop
+ or %g6, 0x10, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- or %g6, 0x10, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_mm
xcall_flush_tlb_mm:
mov SECONDARY_CONTEXT, %g2
- nop
+ mov 0x50, %g4
ldxa [%g2] ASI_DMMU, %g3
- cmp %g3, %g5
- be,pt %icc, 1f
- mov 0x50, %g4
stxa %g5, [%g2] ASI_DMMU
-1: stxa %g0, [%g4] ASI_DMMU_DEMAP
-
- be,pt %icc, 1f
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g4] ASI_DMMU_DEMAP
+ stxa %g0, [%g4] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ retry
- .align 32
- .globl xcall_flush_tlb_range
xcall_flush_tlb_range:
sethi %hi(8192 - 1), %g2
or %g2, %lo(8192 - 1), %g2
@@ -162,26 +133,54 @@ xcall_flush_tlb_range:
andn %g7, %g2, %g7
sub %g7, %g6, %g3
add %g2, 1, %g2
- orcc %g6, 0x50, %g6
+ orcc %g6, 0x10, %g6
srlx %g3, 13, %g4
cmp %g4, 96
bgu,pn %icc, xcall_flush_tlb_mm
mov SECONDARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g7
- cmp %g7, %g5
- be,pt %icc, 1f
- sub %g3, %g2, %g3
+ sub %g3, %g2, %g3
stxa %g5, [%g4] ASI_DMMU
+ nop
+ nop
1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP
stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP
brnz,pt %g3, 1b
sub %g3, %g2, %g3
- bne,a,pn %icc, 1f
- stxa %g7, [%g4] ASI_DMMU
-1: b,pt %xcc, do_ivec_return
- flush %g1
+ stxa %g7, [%g4] ASI_DMMU
+ retry
+ nop
+ nop
+
+ .globl xcall_report_regs
+xcall_report_regs:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call __show_regs
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ b,pt %xcc, rtrap
+ clr %l6
+
+ .globl xcall_capture
+xcall_capture:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ call smp_penguin_jailcell
+ nop
+ b,pt %xcc, rtrap
+ clr %l6
/* These two are not performance critical... */
.globl xcall_flush_tlb_all
@@ -209,8 +208,8 @@ xcall_flush_tlb_all:
cmp %g2, 63
ble,pt %icc, 1b
sll %g2, 3, %g3
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
.globl xcall_flush_cache_all
xcall_flush_cache_all:
@@ -222,6 +221,6 @@ xcall_flush_cache_all:
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
- b,pt %xcc, do_ivec_return
- flush %g1
+ flush %g1
+ retry
#endif /* __SMP__ */
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 40b33da4b..80ba5ec10 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
+/* $Id: console.c,v 1.8 1997/08/16 08:00:16 davem Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
@@ -85,13 +85,13 @@ prom_query_input_device()
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
- if(strncmp(propb, "serial", sizeof("serial")))
+ if(strncmp(propb, "serial", 6))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
- if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
+ if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_I_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_ITTYA;
@@ -114,13 +114,13 @@ prom_query_output_device()
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
return PROMDEV_OSCREEN;
- if(strncmp("serial", propb, sizeof("serial")))
+ if(strncmp("serial", propb, 6))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
- if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
+ if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_O_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_OTTYA;
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index 0703b5cd7..9c5bce294 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
+/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -64,7 +64,7 @@ long p1275_cmd (char *service, long fmt, ...)
long ctx = 0;
p = p1275buf.prom_buffer;
- save_and_cli(flags);
+ __save_and_cli(flags);
ctx = spitfire_get_primary_context ();
if (ctx) {
flushw_user ();
@@ -149,7 +149,7 @@ long p1275_cmd (char *service, long fmt, ...)
if (ctx)
spitfire_set_primary_context (ctx);
- restore_flags(flags);
+ __restore_flags(flags);
return x;
}
diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c
index 323539237..83f860d45 100644
--- a/arch/sparc64/prom/ranges.c
+++ b/arch/sparc64/prom/ranges.c
@@ -1,15 +1,21 @@
-/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
+/* $Id: ranges.c,v 1.8 1997/08/17 22:39:45 ecd Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/sbus.h>
+#include <asm/fhc.h>
#include <asm/system.h>
+#ifdef CONFIG_PCI
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#endif
struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
int num_obio_ranges;
@@ -62,6 +68,25 @@ void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers
}
}
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+ struct linux_prom_registers *regs,
+ int nregs)
+{
+ if(fhc->num_fhc_ranges)
+ prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
+ fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void prom_apply_central_ranges(struct linux_central *central,
+ struct linux_prom_registers *regs, int nregs)
+{
+ if(central->num_central_ranges)
+ prom_adjust_regs(regs, nregs, central->central_ranges,
+ central->num_central_ranges);
+}
+
__initfunc(void prom_ranges_init(void))
{
}
@@ -78,6 +103,56 @@ __initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus))
sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
}
+__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central))
+{
+ int success;
+
+ central->num_central_ranges = 0;
+ success = prom_getproperty(central->prom_node, "ranges",
+ (char *) central->central_ranges,
+ sizeof (central->central_ranges));
+ if (success != -1)
+ central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc))
+{
+ int success;
+
+ fhc->num_fhc_ranges = 0;
+ success = prom_getproperty(fhc->prom_node, "ranges",
+ (char *) fhc->fhc_ranges,
+ sizeof (fhc->fhc_ranges));
+ if (success != -1)
+ fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+#ifdef CONFIG_PCI
+__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
+{
+ int success;
+
+ ebus->num_ebus_ranges = 0;
+ success = prom_getproperty(ebus->prom_node, "ranges",
+ (char *)ebus->ebus_ranges,
+ sizeof(ebus->ebus_ranges));
+ if (success != -1)
+ ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
+}
+
+__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
+{
+ int success;
+
+ pbm->num_pbm_ranges = 0;
+ success = prom_getproperty(pbm->prom_node, "ranges",
+ (char *)&pbm->pbm_ranges,
+ sizeof(pbm->pbm_ranges));
+ if(success != -1)
+ pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
+}
+#endif
+
void
prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
{
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index ae4baf858..c2b386641 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
+/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -26,7 +26,7 @@ __prom_getchild(int node)
__inline__ int
prom_getchild(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = __prom_getchild(node);
@@ -37,7 +37,7 @@ prom_getchild(int node)
__inline__ int
prom_getparent(int node)
{
- long cnode;
+ int cnode;
if(node == -1) return 0;
cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
@@ -57,12 +57,12 @@ __prom_getsibling(int node)
__inline__ int
prom_getsibling(int node)
{
- long sibnode;
+ int sibnode;
if(node == -1) return 0;
sibnode = __prom_getsibling(node);
if(sibnode == -1) return 0;
- return (int)sibnode;
+ return sibnode;
}
/* Return the length in bytes of property 'prop' at node 'node'.
diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
new file mode 100644
index 000000000..56d252962
--- /dev/null
+++ b/arch/sparc64/solaris/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the Solaris binary emulation.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := solaris.o
+O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o
+ifeq ($(CONFIG_SOLARIS_EMUL),m)
+M_OBJS := $(O_TARGET)
+endif
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+ifneq ($(CONFIG_SOLARIS_EMUL),y)
+do_it_all:
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/solaris/conv.h b/arch/sparc64/solaris/conv.h
new file mode 100644
index 000000000..c806d3dc1
--- /dev/null
+++ b/arch/sparc64/solaris/conv.h
@@ -0,0 +1,28 @@
+/* $Id: conv.h,v 1.2 1997/09/03 12:29:13 jj Exp $
+ * conv.h: Utility macros for Solaris emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/* #define DEBUG_SOLARIS */
+
+#ifndef __ASSEMBLY__
+
+#include <asm/unistd.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.
+ */
+#define A(x) ((unsigned long)x)
+
+extern unsigned sys_call_table[];
+extern unsigned sys_call_table32[];
+extern unsigned sunos_sys_table[];
+
+#define SYS(name) ((long)sys_call_table[__NR_##name])
+#define SUNOS(x) ((long)sunos_sys_table[x])
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
new file mode 100644
index 000000000..e983010d1
--- /dev/null
+++ b/arch/sparc64/solaris/entry64.S
@@ -0,0 +1,202 @@
+/* $Id: entry64.S,v 1.3 1997/09/03 12:29:12 jj Exp $
+ * entry64.S: Solaris syscall emulation entry point.
+ *
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/errno.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+#include "conv.h"
+
+#define NR_SYSCALLS 256
+
+ .text
+solaris_syscall_trace:
+ call syscall_trace
+ nop
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ b,pt %xcc, 2f
+ mov %i4, %o4
+
+solaris_sucks:
+/* Solaris is a big system which needs to be able to do all the things
+ * in Inf+1 different ways */
+ add %i6, 0x5c, %o0
+ mov %i0, %g1
+ mov %i1, %i0
+ mov %i2, %i1
+ srl %o0, 0, %o0
+ mov %i3, %i2
+ mov %i4, %i3
+ mov %i5, %i4
+ ba,pt %xcc, solaris_sparc_syscall
+exen: lduwa [%o0] ASI_S, %i5
+
+exenf: ba,pt %xcc, solaris_sparc_syscall
+ clr %i5
+
+/* For shared binaries, binfmt_elf32 already sets up personality
+ and exec_domain. This is to handle static binaries as well */
+solaris_reg:
+ call solaris_register
+ nop
+ ba,pt %xcc, 1f
+ mov %i0, %o0
+
+linux_syscall_for_solaris:
+ sll %l7, 2, %l4
+ ba,pt %xcc, 10f
+ lduw [%l6 + %l4], %l7
+
+ /* Solaris system calls enter here... */
+ .align 32
+ .globl solaris_sparc_syscall
+solaris_sparc_syscall:
+#ifdef DEBUG_SOLARIS
+ mov %g1, %o0
+ call entry_printk
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+#endif
+ ldub [%g6 + AOFF_task_personality + ASIZ_task_personality - 1], %l0
+ cmp %g1, 255
+ bg,pn %icc, solaris_unimplemented
+ srl %g1, 0, %g1
+ sethi %hi(solaris_sys_table), %l7
+ brz,pn %g1, solaris_sucks
+ mov %i0, %o0
+ sll %g1, 2, %l4
+ cmp %l0, 1
+ bne,pn %icc, solaris_reg
+1: mov %i1, %o1
+ lduw [%l7 + %l4], %l7
+ mov %i2, %o2
+ ldx [%g6 + AOFF_task_flags], %l5
+! st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS]
+ cmp %l7, NR_SYSCALLS
+ bleu,a,pn %xcc, linux_syscall_for_solaris
+ sethi %hi(sys_call_table32), %l6
+ andcc %l7, 1, %g0
+ bne,a,pn %icc, 10f
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+10: mov %i3, %o3
+ mov %i4, %o4
+ andn %l7, 3, %l7
+ andcc %l5, 0x20, %g0
+ bne,pn %icc, solaris_syscall_trace
+ mov %i0, %l5
+2: call %l7
+ mov %i5, %o5
+ret_from_solaris:
+#ifdef DEBUG_SOLARIS
+ call exit_printk
+ mov %o0, %l0
+ mov %l0, %o0
+#endif
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ ldx [%g6 + AOFF_task_flags], %l6
+ sra %o0, 0, %o0
+ mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+ cmp %o0, -ENOIOCTLCMD
+ sllx %g2, 32, %g2
+ bgeu,pn %xcc, 1f
+ andcc %l6, 0x20, %l6
+
+ /* System call success, clear Carry condition code. */
+ andn %g3, %g2, %g3
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, solaris_syscall_trace2
+ 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_V9_TPC]
+ clr %l6
+ call rtrap
+ 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
+ cmp %o0, ERANGE /* 0-ERANGE are identity mapped */
+ bleu,pt %icc, 1f
+ cmp %o0, EMEDIUMTYPE
+ bgu,pn %icc, 1f
+ sethi %hi(solaris_err_table), %l6
+ sll %o0, 2, %o0
+ or %l6, %lo(solaris_err_table), %l6
+ ldsw [%l6 + %o0], %o0
+1: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ mov 1, %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, solaris_syscall_trace2
+ 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_V9_TPC]
+ call rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+solaris_syscall_trace2:
+ call syscall_trace
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ call rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+
+ /* This one is tricky, so that's why we do it in assembly */
+ .globl solaris_sigsuspend
+solaris_sigsuspend:
+ call do_sol_sigsuspend
+ nop
+ brlz,pn %o0, ret_from_solaris
+ nop
+ call sys_sigsuspend
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+
+ .globl solaris_getpid
+solaris_getpid:
+ call sys_getppid /* This is tricky, so don't do it in assembly */
+ nop
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+ b,pt %xcc, ret_from_solaris
+ lduw [%g6 + AOFF_task_pid], %o0
+
+ .globl solaris_getuid
+solaris_getuid:
+ lduh [%g6 + AOFF_task_euid], %o1
+ lduh [%g6 + AOFF_task_uid], %o0
+ b,pt %xcc, ret_from_solaris
+ stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+
+ .globl solaris_getgid
+solaris_getgid:
+ lduh [%g6 + AOFF_task_egid], %o1
+ lduh [%g6 + AOFF_task_gid], %o0
+ b,pt %xcc, ret_from_solaris
+ stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+
+ .globl solaris_unimplemented
+solaris_unimplemented:
+ call do_sol_unimplemented
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, ret_from_solaris
+ nop
+
+ .section __ex_table,#alloc
+ .align 4
+ .word exen, exenf
+
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
new file mode 100644
index 000000000..9d0905adc
--- /dev/null
+++ b/arch/sparc64/solaris/fs.c
@@ -0,0 +1,711 @@
+/* $Id: fs.c,v 1.4 1997/09/04 15:46:26 jj Exp $
+ * fs.c: fs related syscall emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/smp_lock.h>
+#include <linux/limits.h>
+#include <linux/resource.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ptrace.h>
+
+#include "conv.h"
+
+extern char * getname32(u32 filename);
+#define putname32 putname
+
+#define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10))
+#define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff)
+#define R4_MINOR(DEV) ((DEV) & 0x3ffff)
+#define R3_VERSION 1
+#define R4_VERSION 2
+
+typedef struct {
+ s32 tv_sec;
+ s32 tv_nsec;
+} timestruct_t;
+
+struct sol_stat {
+ u32 st_dev;
+ s32 st_pad1[3]; /* network id */
+ u32 st_ino;
+ u32 st_mode;
+ u32 st_nlink;
+ u32 st_uid;
+ u32 st_gid;
+ u32 st_rdev;
+ s32 st_pad2[2];
+ s32 st_size;
+ s32 st_pad3; /* st_size, off_t expansion */
+ timestruct_t st_atime;
+ timestruct_t st_mtime;
+ timestruct_t st_ctime;
+ s32 st_blksize;
+ s32 st_blocks;
+ char st_fstype[16];
+ s32 st_pad4[8]; /* expansion area */
+};
+
+#define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
+
+static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf)
+{
+ if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev) ||
+ __put_user (kbuf->st_ino, &ubuf->st_ino) ||
+ __put_user (kbuf->st_mode, &ubuf->st_mode) ||
+ __put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
+ __put_user (kbuf->st_uid, &ubuf->st_uid) ||
+ __put_user (kbuf->st_gid, &ubuf->st_gid) ||
+ __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev) ||
+ __put_user (kbuf->st_size, &ubuf->st_size) ||
+ __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec) ||
+ __put_user (0, &ubuf->st_atime.tv_nsec) ||
+ __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec) ||
+ __put_user (0, &ubuf->st_mtime.tv_nsec) ||
+ __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec) ||
+ __put_user (0, &ubuf->st_ctime.tv_nsec) ||
+ __put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
+ __put_user (kbuf->st_blocks, &ubuf->st_blocks) ||
+ __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_stat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ char *filenam;
+ unsigned long old_fs = get_fs();
+ int (*sys_newstat)(char *,struct stat *) =
+ (int (*)(char *,struct stat *))SYS(stat);
+
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
+ set_fs (KERNEL_DS);
+ ret = sys_newstat(filenam, &s);
+ set_fs (old_fs);
+ putname32 (filenam);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf)
+{
+ /* Solaris doesn't bother with looking at vers, so we do neither */
+ return solaris_stat(filename, statbuf);
+}
+
+asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ char *filenam;
+ unsigned long old_fs = get_fs();
+ int (*sys_newlstat)(char *,struct stat *) =
+ (int (*)(char *,struct stat *))SYS(lstat);
+
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
+ set_fs (KERNEL_DS);
+ ret = sys_newlstat(filenam, &s);
+ set_fs (old_fs);
+ putname32 (filenam);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf)
+{
+ return solaris_lstat(filename, statbuf);
+}
+
+asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ unsigned long old_fs = get_fs();
+ int (*sys_newfstat)(unsigned,struct stat *) =
+ (int (*)(unsigned,struct stat *))SYS(fstat);
+
+ set_fs (KERNEL_DS);
+ ret = sys_newfstat(fd, &s);
+ set_fs (old_fs);
+ if (putstat ((struct sol_stat *)A(statbuf), &s))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf)
+{
+ return solaris_fstat(fd, statbuf);
+}
+
+asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev)
+{
+ int (*sys_mknod)(const char *,int,dev_t) =
+ (int (*)(const char *,int,dev_t))SYS(mknod);
+ int major, minor;
+
+ if ((major = R4_MAJOR(dev)) > 255 ||
+ (minor = R4_MINOR(dev)) > 255) return -EINVAL;
+ return sys_mknod((const char *)A(path), mode, MKDEV(major,minor));
+}
+
+asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev)
+{
+ return solaris_mknod(path, mode, dev);
+}
+
+/* This statfs thingie probably will go in the near future, but... */
+
+struct sol_statfs {
+ short f_type;
+ s32 f_bsize;
+ s32 f_frsize;
+ s32 f_blocks;
+ s32 f_bfree;
+ u32 f_files;
+ u32 f_ffree;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+asmlinkage int solaris_statfs(u32 path, u32 buf, int len, int fstype)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int (*sys_statfs)(const char *,struct statfs *) =
+ (int (*)(const char *,struct statfs *))SYS(statfs);
+ struct sol_statfs *ss = (struct sol_statfs *)A(buf);
+
+ if (len != sizeof(struct sol_statfs)) return -EINVAL;
+ if (!fstype) {
+ set_fs (KERNEL_DS);
+ ret = sys_statfs((const char *)A(path), &s);
+ set_fs (old_fs);
+ if (!ret) {
+ if (put_user (s.f_type, &ss->f_type) ||
+ __put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ }
+ return ret;
+ }
+/* Linux can't stat unmounted filesystems so we
+ * simply lie and claim 100MB of 1GB is free. Sorry.
+ */
+ if (put_user (fstype, &ss->f_type) ||
+ __put_user (1024, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (1024*1024, &ss->f_blocks) ||
+ __put_user (100*1024, &ss->f_bfree) ||
+ __put_user (60000, &ss->f_files) ||
+ __put_user (50000, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_fstatfs(u32 fd, u32 buf, int len, int fstype)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int (*sys_fstatfs)(unsigned,struct statfs *) =
+ (int (*)(unsigned,struct statfs *))SYS(fstatfs);
+ struct sol_statfs *ss = (struct sol_statfs *)A(buf);
+
+ if (len != sizeof(struct sol_statfs)) return -EINVAL;
+ if (!fstype) {
+ set_fs (KERNEL_DS);
+ ret = sys_fstatfs(fd, &s);
+ set_fs (old_fs);
+ if (!ret) {
+ if (put_user (s.f_type, &ss->f_type) ||
+ __put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __clear_user (&ss->f_fname, 12))
+ return -EFAULT;
+ }
+ return ret;
+ }
+ /* Otherwise fstatfs is the same as statfs */
+ return solaris_statfs(0, buf, len, fstype);
+}
+
+struct sol_statvfs {
+ u32 f_bsize;
+ u32 f_frsize;
+ u32 f_blocks;
+ u32 f_bfree;
+ u32 f_bavail;
+ u32 f_files;
+ u32 f_ffree;
+ u32 f_favail;
+ u32 f_fsid;
+ char f_basetype[16];
+ u32 f_flag;
+ u32 f_namemax;
+ char f_fstr[32];
+ u32 f_filler[16];
+};
+
+static int report_statvfs(struct inode *inode, u32 buf)
+{
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+ int error;
+ struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
+
+ set_fs (KERNEL_DS);
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
+ set_fs (old_fs);
+ if (!error) {
+ const char *p = inode->i_sb->s_type->name;
+ int i = 0;
+ int j = strlen (p);
+
+ if (j > 15) j = 15;
+ if (IS_RDONLY(inode)) i = 1;
+ if (IS_NOSUID(inode)) i |= 2;
+ if (put_user (s.f_bsize, &ss->f_bsize) ||
+ __put_user (0, &ss->f_frsize) ||
+ __put_user (s.f_blocks, &ss->f_blocks) ||
+ __put_user (s.f_bfree, &ss->f_bfree) ||
+ __put_user (s.f_bavail, &ss->f_bavail) ||
+ __put_user (s.f_files, &ss->f_files) ||
+ __put_user (s.f_ffree, &ss->f_ffree) ||
+ __put_user (s.f_ffree, &ss->f_favail) ||
+ __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+ __copy_to_user (ss->f_basetype,p,j) ||
+ __put_user (0, (char *)&ss->f_basetype[j]) ||
+ __put_user (s.f_namelen, &ss->f_namemax) ||
+ __put_user (i, &ss->f_flag) ||
+ __clear_user (&ss->f_fstr, 32))
+ return -EFAULT;
+ }
+ return error;
+}
+
+asmlinkage int solaris_statvfs(u32 path, u32 buf)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = namei((const char *)A(path));
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+
+ error = -ENOSYS;
+ if (inode->i_sb->s_op->statfs)
+ error = report_statvfs(inode, buf);
+ dput(dentry);
+ }
+ unlock_kernel();
+ return error;
+}
+
+asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
+{
+ struct inode * inode;
+ struct dentry * dentry;
+ struct file * file;
+ int error;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ error = -EBADF;
+ else if (!(dentry = file->f_dentry))
+ error = -ENOENT;
+ else if (!(inode = dentry->d_inode))
+ error = -ENOENT;
+ else if (!inode->i_sb)
+ error = -ENODEV;
+ else if (!inode->i_sb->s_op->statfs)
+ error = -ENOSYS;
+ else
+ error = report_statvfs(inode, buf);
+ unlock_kernel();
+ return error;
+}
+
+asmlinkage int solaris_open(u32 filename, int flags, u32 mode)
+{
+ int (*sys_open)(const char *,int,int) =
+ (int (*)(const char *,int,int))SYS(open);
+ int fl = flags & 0xf;
+
+ if (flags & 0x8050) fl |= O_SYNC;
+ if (flags & 0x80) fl |= O_NONBLOCK;
+ if (flags & 0x100) fl |= O_CREAT;
+ if (flags & 0x200) fl |= O_TRUNC;
+ if (flags & 0x400) fl |= O_EXCL;
+ if (flags & 0x800) fl |= O_NOCTTY;
+ return sys_open((const char *)A(filename), fl, mode);
+}
+
+#define SOL_F_SETLK 6
+#define SOL_F_SETLKW 7
+#define SOL_F_FREESP 11
+#define SOL_F_ISSTREAM 13
+#define SOL_F_GETLK 14
+#define SOL_F_PRIV 15
+#define SOL_F_NPRIV 16
+#define SOL_F_QUOTACTL 17
+#define SOL_F_BLOCKS 18
+#define SOL_F_BLKSIZE 19
+#define SOL_F_GETOWN 23
+#define SOL_F_SETOWN 24
+
+struct sol_flock {
+ short l_type;
+ short l_whence;
+ u32 l_start;
+ u32 l_len;
+ s32 l_sysid;
+ s32 l_pid;
+ s32 l_pad[4];
+};
+
+asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg)
+{
+ int (*sys_fcntl)(unsigned,unsigned,unsigned long) =
+ (int (*)(unsigned,unsigned,unsigned long))SYS(fcntl);
+ int ret, flags;
+
+ switch (cmd) {
+ case F_DUPFD:
+ case F_GETFD:
+ case F_SETFD: return sys_fcntl(fd, cmd, (unsigned long)arg);
+ case F_GETFL:
+ flags = sys_fcntl(fd, cmd, 0);
+ ret = flags & 0xf;
+ if (flags & O_SYNC) ret |= 0x8050;
+ if (flags & O_NONBLOCK) ret |= 0x80;
+ return ret;
+ case F_SETFL:
+ flags = arg & 0xf;
+ if (arg & 0x8050) flags |= O_SYNC;
+ if (arg & 0x80) flags |= O_NONBLOCK;
+ return sys_fcntl(fd, cmd, (long)flags);
+ case SOL_F_GETLK:
+ case SOL_F_SETLK:
+ case SOL_F_SETLKW:
+ {
+ struct flock f;
+ unsigned long old_fs = get_fs();
+
+ switch (cmd) {
+ case SOL_F_GETLK: cmd = F_GETLK; break;
+ case SOL_F_SETLK: cmd = F_SETLK; break;
+ case SOL_F_SETLKW: cmd = F_SETLKW; break;
+ }
+
+ get_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT);
+ __get_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT);
+ __get_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT);
+ __get_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT);
+ __get_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
+ set_fs(KERNEL_DS);
+ ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+ set_fs(old_fs);
+ __put_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT);
+ __put_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT);
+ __put_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT);
+ __put_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT);
+ __put_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_pid, -EFAULT);
+ __put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
+ return ret;
+ }
+ }
+ return -EINVAL;
+}
+
+asmlinkage int solaris_ulimit(int cmd, int val)
+{
+ switch (cmd) {
+ case 1: /* UL_GETFSIZE - in 512B chunks */
+ return current->rlim[RLIMIT_FSIZE].rlim_cur >> 9;
+ case 2: /* UL_SETFSIZE */
+ if ((unsigned long)val > (LONG_MAX>>9)) return -ERANGE;
+ val <<= 9;
+ lock_kernel();
+ if (val > current->rlim[RLIMIT_FSIZE].rlim_max) {
+ if (!suser()) {
+ unlock_kernel();
+ return -EPERM;
+ }
+ current->rlim[RLIMIT_FSIZE].rlim_max = val;
+ }
+ current->rlim[RLIMIT_FSIZE].rlim_cur = val;
+ unlock_kernel();
+ return 0;
+ case 3: /* UL_GMEMLIM */
+ return current->rlim[RLIMIT_DATA].rlim_cur;
+ case 4: /* UL_GDESLIM */
+ return NR_OPEN;
+ }
+ return -EINVAL;
+}
+
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+{
+ struct inode * inode;
+ struct iattr newattrs;
+ int error;
+
+ error = -ENOENT;
+ if (!(inode = dentry->d_inode)) {
+ printk("chown_common: NULL inode\n");
+ goto out;
+ }
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto out;
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out;
+ if (user == (uid_t) -1)
+ user = inode->i_uid;
+ if (group == (gid_t) -1)
+ group = inode->i_gid;
+ newattrs.ia_mode = inode->i_mode;
+ newattrs.ia_uid = user;
+ newattrs.ia_gid = group;
+ newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
+ /*
+ * If the owner has been changed, remove the setuid bit
+ */
+ if (inode->i_mode & S_ISUID) {
+ newattrs.ia_mode &= ~S_ISUID;
+ newattrs.ia_valid |= ATTR_MODE;
+ }
+ /*
+ * If the group has been changed, remove the setgid bit
+ *
+ * Don't remove the setgid bit if no group execute bit.
+ * This is a file marked for mandatory locking.
+ */
+ if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
+ newattrs.ia_mode &= ~S_ISGID;
+ newattrs.ia_valid |= ATTR_MODE;
+ }
+ if (inode->i_sb && inode->i_sb->dq_op) {
+ inode->i_sb->dq_op->initialize(inode, -1);
+ error = -EDQUOT;
+ if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
+ goto out;
+ error = notify_change(inode, &newattrs);
+ if (error)
+ inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
+ } else
+ error = notify_change(inode, &newattrs);
+out:
+ return error;
+}
+
+/* Linux chown works like Solaris lchown. Solaris chown does follow symlink */
+asmlinkage int solaris_chown(u32 filename, s32 user, s32 group)
+{
+ struct dentry * dentry;
+ int error;
+
+ lock_kernel();
+ dentry = namei((const char *)A(filename));
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = chown_common(dentry, user, group);
+ dput(dentry);
+ }
+ unlock_kernel();
+ return error;
+}
+
+/* At least at the time I'm writing this, Linux doesn't have ACLs, so we
+ just fake this */
+asmlinkage int solaris_acl(u32 filename, int cmd, int nentries, u32 aclbufp)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset)
+{
+ off_t temp;
+ int retval;
+ struct file * file;
+ long (*sys_read)(unsigned int, char *, unsigned long) =
+ (long (*)(unsigned int, char *, unsigned long))SYS(read);
+ long (*sys_lseek)(unsigned int, off_t, unsigned int) =
+ (long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
+
+ lock_kernel();
+ retval = -EBADF;
+ if (fd >= NR_OPEN ||
+ !(file = current->files->fd[fd]))
+ goto bad;
+ temp = file->f_pos;
+ if (temp != offset) {
+ retval = sys_lseek(fd, offset, 0);
+ if (retval < 0) goto bad;
+ }
+ retval = sys_read(fd, (char *)A(buf), nbyte);
+ if (file->f_pos != temp) {
+ if (!retval)
+ retval = sys_lseek(fd, temp, 0);
+ else
+ sys_lseek(fd, temp, 0);
+ }
+bad:
+ unlock_kernel();
+ return retval;
+}
+
+asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset)
+{
+ off_t temp;
+ int retval;
+ struct file * file;
+ long (*sys_write)(unsigned int, char *, unsigned long) =
+ (long (*)(unsigned int, char *, unsigned long))SYS(read);
+ long (*sys_lseek)(unsigned int, off_t, unsigned int) =
+ (long (*)(unsigned int, off_t, unsigned int))SYS(lseek);
+
+ lock_kernel();
+ retval = -EBADF;
+ if (fd >= NR_OPEN ||
+ !(file = current->files->fd[fd]))
+ goto bad;
+ temp = file->f_pos;
+ if (temp != offset) {
+ retval = sys_lseek(fd, offset, 0);
+ if (retval < 0) goto bad;
+ }
+ retval = sys_write(fd, (char *)A(buf), nbyte);
+ if (file->f_pos != temp) {
+ if (!retval)
+ retval = sys_lseek(fd, temp, 0);
+ else
+ sys_lseek(fd, temp, 0);
+ }
+bad:
+ unlock_kernel();
+ return retval;
+}
+
+/* POSIX.1 names */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_NO_TRUNC 7
+#define _PC_VDISABLE 8
+#define _PC_CHOWN_RESTRICTED 9
+/* POSIX.4 names */
+#define _PC_ASYNC_IO 10
+#define _PC_PRIO_IO 11
+#define _PC_SYNC_IO 12
+#define _PC_LAST 12
+
+/* This is not a real and complete implementation yet, just to keep
+ * the easy Solaris binaries happy.
+ */
+asmlinkage int solaris_fpathconf(int fd, int name)
+{
+ int ret;
+
+ switch(name) {
+ case _PC_LINK_MAX:
+ ret = LINK_MAX;
+ break;
+ case _PC_MAX_CANON:
+ ret = MAX_CANON;
+ break;
+ case _PC_MAX_INPUT:
+ ret = MAX_INPUT;
+ break;
+ case _PC_NAME_MAX:
+ ret = NAME_MAX;
+ break;
+ case _PC_PATH_MAX:
+ ret = PATH_MAX;
+ break;
+ case _PC_PIPE_BUF:
+ ret = PIPE_BUF;
+ break;
+ case _PC_CHOWN_RESTRICTED:
+ ret = 1;
+ break;
+ case _PC_NO_TRUNC:
+ case _PC_VDISABLE:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_pathconf(u32 path, int name)
+{
+ return solaris_fpathconf(0, name);
+}
+
+/* solaris_llseek returns long long - quite difficult */
+asmlinkage long solaris_llseek(struct pt_regs *regs, u32 off_hi, u32 off_lo, int whence)
+{
+ int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int) =
+ (int (*)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int))SYS(_llseek);
+ int ret;
+ unsigned long old_fs = get_fs();
+ loff_t retval;
+
+ set_fs(KERNEL_DS);
+ ret = sys_llseek((unsigned int)regs->u_regs[UREG_I0], off_hi, off_lo, &retval, whence);
+ set_fs(old_fs);
+ if (ret < 0) return ret;
+ regs->u_regs[UREG_I1] = (u32)retval;
+ return (retval >> 32);
+}
+
+/* Have to mask out all but lower 3 bits */
+asmlinkage int solaris_access(u32 filename, long mode)
+{
+ int (*sys_access)(const char *, int) =
+ (int (*)(const char *, int))SYS(access);
+
+ return sys_access((const char *)A(filename), mode & 7);
+}
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
new file mode 100644
index 000000000..43b844caf
--- /dev/null
+++ b/arch/sparc64/solaris/ioctl.c
@@ -0,0 +1,316 @@
+/* $Id: ioctl.c,v 1.2 1997/09/04 00:59:22 davem Exp $
+ * ioctl.c: Solaris ioctl emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Streams & timod emulation based on code
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+
+extern char * getname32(u32 filename);
+#define putname32 putname
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg);
+extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,
+ u32 arg);
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
+/* termio* stuff {{{ */
+
+struct solaris_termios {
+ u32 c_iflag;
+ u32 c_oflag;
+ u32 c_cflag;
+ u32 c_lflag;
+ u8 c_cc[19];
+};
+
+struct solaris_termio {
+ u16 c_iflag;
+ u16 c_oflag;
+ u16 c_cflag;
+ u16 c_lflag;
+ s8 c_line;
+ u8 c_cc[8];
+};
+
+struct solaris_termiox {
+ u16 x_hflag;
+ u16 x_cflag;
+ u16 x_rflag[5];
+ u16 x_sflag;
+};
+
+static u32 solaris_to_linux_cflag(u32 cflag)
+{
+ cflag &= 0x7fdff000;
+ if (cflag & 0x200000) {
+ int baud = cflag & 0xf;
+ cflag &= ~0x20000f;
+ switch (baud) {
+ case 0: baud = B57600; break;
+ case 1: baud = B76800; break;
+ case 2: baud = B115200; break;
+ case 3: baud = B153600; break;
+ case 4: baud = B230400; break;
+ case 5: baud = B307200; break;
+ case 6: baud = B460800; break;
+ }
+ cflag |= CBAUDEX | baud;
+ }
+ return cflag;
+}
+
+static u32 linux_to_solaris_cflag(u32 cflag)
+{
+ cflag &= ~(CMSPAR | CIBAUD);
+ if (cflag & CBAUDEX) {
+ int baud = cflag & CBAUD;
+ cflag &= ~CBAUD;
+ switch (baud) {
+ case B57600: baud = 0; break;
+ case B76800: baud = 1; break;
+ case B115200: baud = 2; break;
+ case B153600: baud = 3; break;
+ case B230400: baud = 4; break;
+ case B307200: baud = 5; break;
+ case B460800: baud = 6; break;
+ case B614400: baud = 7; break;
+ case B921600: baud = 8; break;
+ /* case B1843200: baud = 9; break; */
+ }
+ cflag |= 0x200000 | baud;
+ }
+ return cflag;
+}
+
+static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+
+ ret = sys_ioctl(fd, cmd, A(arg));
+ if (!ret) {
+ u32 cflag;
+
+ if (__get_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
+ return -EFAULT;
+ cflag = linux_to_solaris_cflag(cflag);
+ if (__put_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termio s;
+ unsigned long old_fs = get_fs();
+
+ if (copy_from_user (&s, (struct solaris_termio *)A(arg), sizeof(struct solaris_termio)))
+ return -EFAULT;
+ s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ return ret;
+}
+
+static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termios s;
+ unsigned long old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ if (!ret) {
+ if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
+ __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
+ __put_user (linux_to_solaris_cflag(s.c_cflag), &((struct solaris_termios *)A(arg))->c_cflag) ||
+ __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
+ __copy_to_user (((struct solaris_termios *)A(arg))->c_cc, s.c_cc, 16) ||
+ __clear_user (((struct solaris_termios *)A(arg))->c_cc + 16, 2))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int solaris_to_linux_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+ struct solaris_termios s;
+ unsigned long old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, TCGETS, (unsigned long)&s);
+ set_fs(old_fs);
+ if (ret) return ret;
+ if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) ||
+ __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) ||
+ __put_user (s.c_cflag, &((struct solaris_termios *)A(arg))->c_cflag) ||
+ __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) ||
+ __copy_from_user (s.c_cc, ((struct solaris_termios *)A(arg))->c_cc, 16))
+ return -EFAULT;
+ s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+ set_fs(old_fs);
+ return ret;
+}
+
+static inline int solaris_T(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd & 0xff) {
+ case 1: /* TCGETA */
+ return linux_to_solaris_termio(fd, TCGETA, arg);
+ case 2: /* TCSETA */
+ return solaris_to_linux_termio(fd, TCSETA, arg);
+ case 3: /* TCSETAW */
+ return solaris_to_linux_termio(fd, TCSETAW, arg);
+ case 4: /* TCSETAF */
+ return solaris_to_linux_termio(fd, TCSETAF, arg);
+ case 5: /* TCSBRK */
+ return sys_ioctl(fd, TCSBRK, arg);
+ case 6: /* TCXONC */
+ return sys_ioctl(fd, TCXONC, arg);
+ case 7: /* TCFLSH */
+ return sys_ioctl(fd, TCFLSH, arg);
+ case 13: /* TCGETS */
+ return linux_to_solaris_termios(fd, TCGETS, arg);
+ case 14: /* TCSETS */
+ return solaris_to_linux_termios(fd, TCSETS, arg);
+ case 15: /* TCSETSW */
+ return solaris_to_linux_termios(fd, TCSETSW, arg);
+ case 16: /* TCSETSF */
+ return solaris_to_linux_termios(fd, TCSETSF, arg);
+ case 103: /* TIOCSWINSZ */
+ return sys_ioctl(fd, TIOCSWINSZ, arg);
+ case 104: /* TIOCGWINSZ */
+ return sys_ioctl(fd, TIOCGWINSZ, arg);
+ }
+ return -ENOSYS;
+}
+
+static inline int solaris_t(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd & 0xff) {
+ case 20: /* TIOCGPGRP */
+ return sys_ioctl(fd, TIOCGPGRP, arg);
+ case 21: /* TIOCSPGRP */
+ return sys_ioctl(fd, TIOCSPGRP, arg);
+ }
+ return -ENOSYS;
+}
+
+/* }}} */
+
+/* A pseudo STREAMS support {{{ */
+
+struct strioctl {
+ int cmd, timeout, len;
+ u32 data;
+};
+
+static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ char *p;
+ int ret;
+ unsigned long old_fs;
+ struct strioctl si;
+
+ switch (cmd & 0xff) {
+ case 1: /* I_NREAD */
+ return -ENOSYS;
+ case 2: /* I_PUSH */
+ p = getname32 (arg);
+ if (IS_ERR (p))
+ return PTR_ERR(p);
+ putname32 (p);
+ return 0;
+ case 3: /* I_POP */
+ return 0;
+ case 5: /* I_FLUSH */
+ return 0;
+ case 8: /* I_STR */
+ if (copy_from_user (&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
+ return -EFAULT;
+ switch ((si.cmd >> 8) & 0xff) {
+ case 'T':
+ default:
+ return solaris_ioctl(fd, si.cmd, si.data);
+ }
+ case 9: /* I_SETSIG */
+ return sys_ioctl(fd, FIOSETOWN, current->pid);
+ case 10: /* I_GETSIG */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ sys_ioctl(fd, FIOGETOWN, (unsigned long)&ret);
+ set_fs(old_fs);
+ if (ret == current->pid) return 0x3ff;
+ else return -EINVAL;
+ case 11: /* I_FIND */
+ p = getname32 (arg);
+ if (IS_ERR (p))
+ return PTR_ERR(p);
+ ret = !strcmp(p, "timod");
+ putname32 (p);
+ return ret;
+ }
+ return -ENOSYS;
+}
+/* }}} */
+
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct file * filp;
+ int error = -EBADF;
+
+ lock_kernel();
+ if(fd >= NR_OPEN) goto out;
+
+ filp = current->files->fd[fd];
+ if(!filp) goto out;
+
+ if (!filp->f_op || !filp->f_op->ioctl) {
+ error = sys_ioctl (fd, cmd, (unsigned long)arg);
+ goto out;
+ }
+
+ error = -EFAULT;
+ switch ((cmd >> 8) & 0xff) {
+ case 'S': error = solaris_S(fd, cmd, arg); break;
+ case 'T': error = solaris_T(fd, cmd, arg); break;
+ case 't': error = solaris_t(fd, cmd, arg); break;
+ default:
+ error = -ENOSYS;
+ break;
+ }
+out:
+ if (error == -ENOSYS) {
+ unsigned char c = cmd>>8;
+
+ if (c < ' ' || c > 126) c = '.';
+ printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, c, (unsigned int)arg);
+ error = -EINVAL;
+ }
+ unlock_kernel();
+ return error;
+}
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
new file mode 100644
index 000000000..132028447
--- /dev/null
+++ b/arch/sparc64/solaris/ipc.c
@@ -0,0 +1,122 @@
+/* $Id: ipc.c,v 1.1 1997/09/03 12:29:29 jj Exp $
+ * ipc.c: Solaris IPC emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ipc.h>
+
+#include "conv.h"
+
+struct solaris_ipc_perm {
+ s32 uid;
+ s32 gid;
+ s32 cuid;
+ s32 cgid;
+ u32 mode;
+ u32 seq;
+ int key;
+ s32 pad[4];
+};
+
+struct solaris_shmid_ds {
+ struct solaris_ipc_perm shm_perm;
+ int shm_segsz;
+ u32 shm_amp;
+ unsigned short shm_lkcnt;
+ char __padxx[2];
+ s32 shm_lpid;
+ s32 shm_cpid;
+ u32 shm_nattch;
+ u32 shm_cnattch;
+ s32 shm_atime;
+ s32 shm_pad1;
+ s32 shm_dtime;
+ s32 shm_pad2;
+ s32 shm_ctime;
+ s32 shm_pad3;
+ unsigned short shm_cv;
+ char shm_pad4[2];
+ u32 shm_sptas;
+ s32 shm_pad5[2];
+};
+
+asmlinkage long solaris_shmsys(int cmd, u32 arg1, u32 arg2, u32 arg3)
+{
+ int (*sys_ipc)(unsigned,int,int,unsigned long,void *,long) =
+ (int (*)(unsigned,int,int,unsigned long,void *,long))SYS(ipc);
+ unsigned long old_fs;
+ unsigned long raddr;
+ int ret;
+
+ switch (cmd) {
+ case 0: /* shmat */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMAT, arg1, arg3 & ~0x4000, (unsigned long)&raddr, (void *)A(arg2), 0);
+ set_fs(old_fs);
+ if (ret >= 0) return (u32)raddr;
+ else return ret;
+ case 1: /* shmctl */
+ switch (arg2) {
+ case 3: /* SHM_LOCK */
+ case 4: /* SHM_UNLOCK */
+ return sys_ipc(SHMCTL, arg1, (arg2 == 3) ? SHM_LOCK : SHM_UNLOCK, 0, NULL, 0);
+ case 10: /* IPC_RMID */
+ return sys_ipc(SHMCTL, arg1, IPC_RMID, 0, NULL, 0);
+ case 11: /* IPC_SET */
+ {
+ struct shmid_ds s;
+
+ if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) ||
+ __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) ||
+ __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode)))
+ return -EFAULT;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+ set_fs(old_fs);
+ return ret;
+ }
+ case 12: /* IPC_STAT */
+ {
+ struct shmid_ds s;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+ set_fs(old_fs);
+ if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) ||
+ __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) ||
+ __get_user (s.shm_perm.cuid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cuid)) ||
+ __get_user (s.shm_perm.cgid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cgid)) ||
+ __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode)) ||
+ __get_user (s.shm_perm.seq, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.seq)) ||
+ __get_user (s.shm_perm.key, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.key)) ||
+ __get_user (s.shm_segsz, &(((struct solaris_shmid_ds *)A(arg3))->shm_segsz)) ||
+ __get_user (s.shm_lpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_lpid)) ||
+ __get_user (s.shm_cpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_cpid)) ||
+ __get_user (s.shm_nattch, &(((struct solaris_shmid_ds *)A(arg3))->shm_nattch)) ||
+ __get_user (s.shm_atime, &(((struct solaris_shmid_ds *)A(arg3))->shm_atime)) ||
+ __get_user (s.shm_dtime, &(((struct solaris_shmid_ds *)A(arg3))->shm_dtime)) ||
+ __get_user (s.shm_ctime, &(((struct solaris_shmid_ds *)A(arg3))->shm_ctime)))
+ return -EFAULT;
+ return ret;
+ }
+ default: return -EINVAL;
+ }
+ case 2: /* shmdt */
+ return sys_ipc(SHMDT, 0, 0, 0, (void *)A(arg1), 0);
+ case 3: /* shmget */
+ return sys_ipc(SHMGET, arg1, arg2, arg3, NULL, 0);
+ }
+ return -EINVAL;
+}
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
new file mode 100644
index 000000000..fdabd0e26
--- /dev/null
+++ b/arch/sparc64/solaris/misc.c
@@ -0,0 +1,463 @@
+/* $Id: misc.c,v 1.4 1997/09/04 14:57:31 jj Exp $
+ * misc.c: Miscelaneous syscall emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#include "conv.h"
+
+/* Conversion from Linux to Solaris errnos. 0-34 are identity mapped.
+ Some Linux errnos (EPROCLIM, EDOTDOT, ERREMOTE, EUCLEAN, ENOTNAM,
+ ENAVAIL, EISNAM, EREMOTEIO, ENOMEDIUM, EMEDIUMTYPE) have no Solaris
+ equivalents. I return EINVAL in that case, which is very wrong. If
+ someone suggest a better value for them, you're welcomed.
+ On the other side, Solaris ECANCELED and ENOTSUP have no Linux equivalents,
+ but that doesn't matter here. --jj */
+int solaris_err_table[] = {
+/* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+/* 10 */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+/* 20 */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+/* 30 */ 30, 31, 32, 33, 34, 22, 150, 149, 95, 96,
+/* 40 */ 97, 98, 99, 120, 121, 122, 123, 124, 125, 126,
+/* 50 */ 127, 128, 129, 130, 131, 132, 133, 134, 143, 144,
+/* 60 */ 145, 146, 90, 78, 147, 148, 93, 22, 94, 49,
+/* 70 */ 151, 66, 60, 62, 63, 35, 77, 36, 45, 46,
+/* 80 */ 64, 22, 67, 68, 69, 70, 71, 74, 22, 82,
+/* 90 */ 89, 92, 79, 81, 37, 38, 39, 40, 41, 42,
+/* 100 */ 43, 44, 50, 51, 52, 53, 54, 55, 56, 57,
+/* 110 */ 87, 61, 84, 65, 83, 80, 91, 22, 22, 22,
+/* 120 */ 22, 22, 88, 86, 85, 22, 22,
+};
+
+asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+ u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) =
+ (u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71);
+ u32 ret;
+
+ ret = sunos_mmap(addr,len,prot,flags,fd,off);
+ /* sunos_mmap sets personality to PER_BSD */
+ current->personality = PER_SVR4;
+ return ret;
+}
+
+asmlinkage int solaris_brk(u32 brk)
+{
+ int (*sunos_brk)(u32) = (int (*)(u32))SUNOS(17);
+
+ return sunos_brk(brk);
+}
+
+#define set_utsfield(to, from, dotchop, countfrom) { \
+ char *p; \
+ int i, len = (countfrom) ? \
+ ((sizeof(to) > sizeof(from) ? \
+ sizeof(from) : sizeof(to))) : sizeof(to); \
+ copy_to_user_ret(to, from, len, -EFAULT); \
+ if (dotchop) \
+ for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \
+ else \
+ i = len - 1; \
+ __put_user_ret('\0', (char *)(to+i), -EFAULT); \
+}
+
+struct sol_uname {
+ char sysname[9];
+ char nodename[9];
+ char release[9];
+ char version[9];
+ char machine[9];
+};
+
+struct sol_utsname {
+ char sysname[257];
+ char nodename[257];
+ char release[257];
+ char version[257];
+ char machine[257];
+};
+
+static char *machine(void)
+{
+ switch (sparc_cpu_model) {
+ case sun4: return "sun4";
+ case sun4c: return "sun4c";
+ case sun4e: return "sun4e";
+ case sun4m: return "sun4m";
+ case sun4d: return "sun4d";
+ case sun4u: return "sun4u";
+ default: return "sparc";
+ }
+}
+
+static char *platform(char *buffer)
+{
+ int i;
+ struct {
+ char *platform;
+ int id_machtype;
+ } platforms [] = {
+ { "sun4", (SM_SUN4 | SM_4_110) },
+ { "sun4", (SM_SUN4 | SM_4_260) },
+ { "sun4", (SM_SUN4 | SM_4_330) },
+ { "sun4", (SM_SUN4 | SM_4_470) },
+ { "SUNW,Sun_4_60", (SM_SUN4C | SM_4C_SS1) },
+ { "SUNW,Sun_4_40", (SM_SUN4C | SM_4C_IPC) },
+ { "SUNW,Sun_4_65", (SM_SUN4C | SM_4C_SS1PLUS) },
+ { "SUNW,Sun_4_20", (SM_SUN4C | SM_4C_SLC) },
+ { "SUNW,Sun_4_75", (SM_SUN4C | SM_4C_SS2) },
+ { "SUNW,Sun_4_25", (SM_SUN4C | SM_4C_ELC) },
+ { "SUNW,Sun_4_50", (SM_SUN4C | SM_4C_IPX) },
+ { "SUNW,Sun_4_600", (SM_SUN4M | SM_4M_SS60) },
+ { "SUNW,SPARCstation-5", (SM_SUN4M | SM_4M_SS50) },
+ { "SUNW,SPARCstation-20", (SM_SUN4M | SM_4M_SS40) }
+ };
+
+ *buffer = 0;
+ prom_getproperty(prom_root_node, "name", buffer, 256);
+ if (*buffer) {
+ char *p;
+
+ for (p = buffer; *p; p++)
+ if (*p == '/' || *p == ' ') *p = '_';
+ return buffer;
+ }
+ for (i = 0; i < sizeof (platforms)/sizeof (platforms[0]); i++)
+ if (platforms[i].id_machtype == idprom->id_machtype)
+ return platforms[i].platform;
+ return "sun4c";
+}
+
+static char *serial(char *buffer)
+{
+ int node = prom_getchild(prom_root_node);
+
+ node = prom_searchsiblings(node, "options");
+ *buffer = 0;
+ prom_getproperty(node, "system-board-serial#", buffer, 256);
+ if (!*buffer)
+ return "4512348717234";
+ else
+ return buffer;
+}
+
+asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
+{
+ switch (which) {
+ case 0: /* old uname */
+ /* Lets cheat */
+ set_utsfield(((struct sol_uname *)A(buf))->sysname,
+ "SunOS", 1, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->nodename,
+ system_utsname.nodename, 1, 1);
+ set_utsfield(((struct sol_uname *)A(buf))->release,
+ "2.6", 0, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->version,
+ "Generic", 0, 0);
+ set_utsfield(((struct sol_uname *)A(buf))->machine,
+ machine(), 0, 0);
+ return 0;
+ case 2: /* ustat */
+ return -ENOSYS;
+ case 3: /* fusers */
+ return -ENOSYS;
+ default:
+ return -ENOSYS;
+ }
+}
+
+asmlinkage int solaris_utsname(u32 buf)
+{
+ /* Why should we not lie a bit? */
+ set_utsfield(((struct sol_utsname *)A(buf))->sysname,
+ "SunOS", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->nodename,
+ system_utsname.nodename, 1, 1);
+ set_utsfield(((struct sol_utsname *)A(buf))->release,
+ "5.6", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->version,
+ "Generic", 0, 0);
+ set_utsfield(((struct sol_utsname *)A(buf))->machine,
+ machine(), 0, 0);
+ return 0;
+}
+
+#define SI_SYSNAME 1 /* return name of operating system */
+#define SI_HOSTNAME 2 /* return name of node */
+#define SI_RELEASE 3 /* return release of operating system */
+#define SI_VERSION 4 /* return version field of utsname */
+#define SI_MACHINE 5 /* return kind of machine */
+#define SI_ARCHITECTURE 6 /* return instruction set arch */
+#define SI_HW_SERIAL 7 /* return hardware serial number */
+#define SI_HW_PROVIDER 8 /* return hardware manufacturer */
+#define SI_SRPC_DOMAIN 9 /* return secure RPC domain */
+#define SI_PLATFORM 513 /* return platform identifier */
+
+asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
+{
+ char *p, *q, *r;
+ char buffer[256];
+ int len;
+
+ /* Again, we cheat :)) */
+ switch (cmd) {
+ case SI_SYSNAME: r = "SunOS"; break;
+ case SI_HOSTNAME:
+ r = buffer + 256;
+ for (p = system_utsname.nodename, q = buffer;
+ q < r && *p && *p != '.'; *q++ = *p++);
+ *q = 0;
+ r = buffer;
+ break;
+ case SI_RELEASE: r = "5.6"; break;
+ case SI_MACHINE: r = machine(); break;
+ case SI_ARCHITECTURE: r = "sparc"; break;
+ case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
+ case SI_HW_SERIAL: r = serial(buffer); break;
+ case SI_PLATFORM: r = platform(buffer); break;
+ case SI_SRPC_DOMAIN: r = ""; break;
+ case SI_VERSION: r = "Generic"; break;
+ default: return -EINVAL;
+ }
+ len = strlen(r) + 1;
+ if (count < len) {
+ copy_to_user_ret((char *)A(buf), r, count - 1, -EFAULT);
+ __put_user_ret(0, (char *)A(buf) + count - 1, -EFAULT);
+ } else
+ copy_to_user_ret((char *)A(buf), r, len, -EFAULT);
+ return len;
+}
+
+#define SOLARIS_CONFIG_NGROUPS 2
+#define SOLARIS_CONFIG_CHILD_MAX 3
+#define SOLARIS_CONFIG_OPEN_FILES 4
+#define SOLARIS_CONFIG_POSIX_VER 5
+#define SOLARIS_CONFIG_PAGESIZE 6
+#define SOLARIS_CONFIG_CLK_TCK 7
+#define SOLARIS_CONFIG_XOPEN_VER 8
+#define SOLARIS_CONFIG_PROF_TCK 10
+#define SOLARIS_CONFIG_NPROC_CONF 11
+#define SOLARIS_CONFIG_NPROC_ONLN 12
+#define SOLARIS_CONFIG_AIO_LISTIO_MAX 13
+#define SOLARIS_CONFIG_AIO_MAX 14
+#define SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX 15
+#define SOLARIS_CONFIG_DELAYTIMER_MAX 16
+#define SOLARIS_CONFIG_MQ_OPEN_MAX 17
+#define SOLARIS_CONFIG_MQ_PRIO_MAX 18
+#define SOLARIS_CONFIG_RTSIG_MAX 19
+#define SOLARIS_CONFIG_SEM_NSEMS_MAX 20
+#define SOLARIS_CONFIG_SEM_VALUE_MAX 21
+#define SOLARIS_CONFIG_SIGQUEUE_MAX 22
+#define SOLARIS_CONFIG_SIGRT_MIN 23
+#define SOLARIS_CONFIG_SIGRT_MAX 24
+#define SOLARIS_CONFIG_TIMER_MAX 25
+#define SOLARIS_CONFIG_PHYS_PAGES 26
+#define SOLARIS_CONFIG_AVPHYS_PAGES 27
+
+asmlinkage int solaris_sysconf(int id)
+{
+ switch (id) {
+ case SOLARIS_CONFIG_NGROUPS: return NGROUPS_MAX;
+ case SOLARIS_CONFIG_CHILD_MAX: return CHILD_MAX;
+ case SOLARIS_CONFIG_OPEN_FILES: return OPEN_MAX;
+ case SOLARIS_CONFIG_POSIX_VER: return 199309;
+ case SOLARIS_CONFIG_PAGESIZE: return PAGE_SIZE;
+ case SOLARIS_CONFIG_XOPEN_VER: return 3;
+ case SOLARIS_CONFIG_CLK_TCK:
+ case SOLARIS_CONFIG_PROF_TCK:
+ return prom_getintdefault(
+ linux_cpus[smp_processor_id()].prom_node,
+ "clock-frequency", 167000000);
+#ifdef __SMP__
+ case SOLARIS_CONFIG_NPROC_CONF: return NCPUS;
+ case SOLARIS_CONFIG_NPROC_ONLN: return smp_num_cpus;
+#else
+ case SOLARIS_CONFIG_NPROC_CONF: return 1;
+ case SOLARIS_CONFIG_NPROC_ONLN: return 1;
+#endif
+ case SOLARIS_CONFIG_SIGRT_MIN: return 37;
+ case SOLARIS_CONFIG_SIGRT_MAX: return 44;
+ case SOLARIS_CONFIG_PHYS_PAGES:
+ case SOLARIS_CONFIG_AVPHYS_PAGES:
+ {
+ struct sysinfo s;
+
+ si_meminfo(&s);
+ if (id == SOLARIS_CONFIG_PHYS_PAGES)
+ return s.totalram >>= PAGE_SHIFT;
+ else
+ return s.freeram >>= PAGE_SHIFT;
+ }
+ /* XXX support these as well -jj */
+ case SOLARIS_CONFIG_AIO_LISTIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_AIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_DELAYTIMER_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_MQ_OPEN_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_MQ_PRIO_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_RTSIG_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SEM_NSEMS_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SEM_VALUE_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_SIGQUEUE_MAX: return -EINVAL;
+ case SOLARIS_CONFIG_TIMER_MAX: return -EINVAL;
+ default: return -EINVAL;
+ }
+}
+
+asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
+{
+ int ret;
+
+ switch (cmd) {
+ case 0: /* getpgrp */
+ return current->pgrp;
+ case 1: /* setpgrp */
+ {
+ int (*sys_setpgid)(pid_t,pid_t) =
+ (int (*)(pid_t,pid_t))SYS(setpgid);
+
+ /* can anyone explain me the difference between
+ Solaris setpgrp and setsid? */
+ ret = sys_setpgid(0, 0);
+ if (ret) return ret;
+ current->tty = NULL;
+ return current->pgrp;
+ }
+ case 2: /* getsid */
+ {
+ int (*sys_getsid)(pid_t) = (int (*)(pid_t))SYS(getsid);
+ return sys_getsid(pid);
+ }
+ case 3: /* setsid */
+ {
+ int (*sys_setsid)(void) = (int (*)(void))SYS(setsid);
+ return sys_setsid();
+ }
+ case 4: /* getpgid */
+ {
+ int (*sys_getpgid)(pid_t) = (int (*)(pid_t))SYS(getpgid);
+ return sys_getpgid(pid);
+ }
+ case 5: /* setpgid */
+ {
+ int (*sys_setpgid)(pid_t,pid_t) =
+ (int (*)(pid_t,pid_t))SYS(setpgid);
+ return sys_setpgid(pid,pgid);
+ }
+ }
+ return -EINVAL;
+}
+
+asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
+{
+ printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n",
+ (int)regs->u_regs[UREG_G1],
+ (int)regs->u_regs[UREG_I0],
+ (int)regs->u_regs[UREG_I1],
+ (int)regs->u_regs[UREG_I2],
+ (int)regs->u_regs[UREG_I3]);
+ return -ENOSYS;
+}
+
+asmlinkage void solaris_register(void)
+{
+ lock_kernel();
+ current->personality = PER_SVR4;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_DEC_USE_COUNT(current->exec_domain->module);
+ current->exec_domain = lookup_exec_domain(current->personality);
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_INC_USE_COUNT(current->exec_domain->module);
+ unlock_kernel();
+}
+
+extern long solaris_to_linux_signals[], linux_to_solaris_signals[];
+
+struct exec_domain solaris_exec_domain = {
+ "Solaris",
+ (lcall7_func)NULL,
+ 1, 1, /* PER_SVR4 personality */
+ solaris_to_linux_signals,
+ linux_to_solaris_signals,
+#ifdef MODULE
+ &__this_module,
+#else
+ NULL,
+#endif
+ NULL
+};
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz)");
+MODULE_DESCRIPTION("Solaris binary emulation module");
+
+#ifdef __sparc_v9__
+extern u32 tl0_solaris[8];
+#define update_ttable(x) \
+ tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \
+ __asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3]))
+#else
+#endif
+
+extern u32 solaris_sparc_syscall[];
+extern u32 solaris_syscall[];
+extern int init_socksys(void);
+extern void cleanup_socksys(void);
+
+int init_module(void)
+{
+ int ret;
+ register_exec_domain(&solaris_exec_domain);
+ if ((ret = init_socksys())) {
+ unregister_exec_domain(&solaris_exec_domain);
+ return ret;
+ }
+ update_ttable(solaris_sparc_syscall);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ update_ttable(solaris_syscall);
+ cleanup_socksys();
+ unregister_exec_domain(&solaris_exec_domain);
+}
+
+#else
+int init_solaris_emul(void)
+{
+ register_exec_domain(&solaris_exec_domain);
+ init_socksys();
+}
+#endif
+
+#ifdef DEBUG_SOLARIS
+void entry_printk(int sysno, struct pt_regs *regs)
+{
+ printk ("Entering %d\n", sysno);
+ printk ("%08x %08x %08x %08x\n", (int)regs->u_regs[UREG_I0],
+ (int)regs->u_regs[UREG_I1],
+ (int)regs->u_regs[UREG_I2],
+ (int)regs->u_regs[UREG_I3]);
+}
+
+void exit_printk(unsigned long ret)
+{
+ printk ("Returning %016lx\n", ret);
+}
+#endif
diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
new file mode 100644
index 000000000..6d3081c03
--- /dev/null
+++ b/arch/sparc64/solaris/signal.c
@@ -0,0 +1,419 @@
+/* $Id: signal.c,v 1.2 1997/09/03 12:29:19 jj Exp $
+ * signal.c: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/svr4.h>
+#include <asm/string.h>
+
+#include "conv.h"
+#include "signal.h"
+
+#define _S(nr) (1L<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+long linux_to_solaris_signals[] = {
+ 0,
+ SOLARIS_SIGHUP, SOLARIS_SIGINT,
+ SOLARIS_SIGQUIT, SOLARIS_SIGILL,
+ SOLARIS_SIGTRAP, SOLARIS_SIGIOT,
+ SOLARIS_SIGEMT, SOLARIS_SIGFPE,
+ SOLARIS_SIGKILL, SOLARIS_SIGBUS,
+ SOLARIS_SIGSEGV, SOLARIS_SIGSYS,
+ SOLARIS_SIGPIPE, SOLARIS_SIGALRM,
+ SOLARIS_SIGTERM, SOLARIS_SIGURG,
+ SOLARIS_SIGSTOP, SOLARIS_SIGTSTP,
+ SOLARIS_SIGCONT, SOLARIS_SIGCLD,
+ SOLARIS_SIGTTIN, SOLARIS_SIGTTOU,
+ SOLARIS_SIGPOLL, SOLARIS_SIGXCPU,
+ SOLARIS_SIGXFSZ, SOLARIS_SIGVTALRM,
+ SOLARIS_SIGPROF, SOLARIS_SIGWINCH,
+ SOLARIS_SIGUSR1, SOLARIS_SIGUSR1,
+ SOLARIS_SIGUSR2, -1,
+};
+
+long solaris_to_linux_signals[] = {
+ 0,
+ SIGHUP, SIGINT, SIGQUIT, SIGILL,
+ SIGTRAP, SIGIOT, SIGEMT, SIGFPE,
+ SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
+ SIGPIPE, SIGALRM, SIGTERM, SIGUSR1,
+ SIGUSR2, SIGCHLD, -1, SIGWINCH,
+ SIGURG, SIGPOLL, SIGSTOP, SIGTSTP,
+ SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM,
+ SIGPROF, SIGXCPU, SIGXFSZ, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+};
+
+static inline long mapsig(long sig)
+{
+ if ((unsigned long)sig > SOLARIS_NSIGNALS)
+ return -EINVAL;
+ return solaris_to_linux_signals[sig];
+}
+
+asmlinkage int solaris_kill(int pid, int sig)
+{
+ int (*sys_kill)(int,int) =
+ (int (*)(int,int))SYS(kill);
+ int s = mapsig(sig);
+
+ if (s < 0) return s;
+ return sys_kill(pid, s);
+}
+
+static long sig_handler(int sig, u32 arg, int one_shot)
+{
+ struct sigaction sa, old;
+ int ret;
+ unsigned long old_fs = get_fs();
+ int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) =
+ (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
+
+ sa.sa_mask = 0L;
+ sa.sa_restorer = NULL;
+ sa.sa_handler = (__sighandler_t)A(arg);
+ sa.sa_flags = 0;
+ if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+ set_fs (KERNEL_DS);
+ ret = sys_sigaction(sig, &sa, &old);
+ set_fs (old_fs);
+ if (ret < 0) return ret;
+ return (u32)(long)old.sa_handler;
+}
+
+static inline long solaris_signal(int sig, u32 arg)
+{
+ return sig_handler (sig, arg, 1);
+}
+
+static long solaris_sigset(int sig, u32 arg)
+{
+ if (arg != 2) /* HOLD */ {
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked &= ~_S(sig);
+ spin_unlock_irq(&current->sigmask_lock);
+ return sig_handler (sig, arg, 0);
+ } else {
+ sigset_t n = _S(sig) & _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked |= n;
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+ }
+}
+
+static inline long solaris_sighold(int sig)
+{
+ return solaris_sigset(sig, 2);
+}
+
+static inline long solaris_sigrelse(int sig)
+{
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked &= ~_S(sig);
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+}
+
+static inline long solaris_sigignore(int sig)
+{
+ return sig_handler (sig, (u32)SIG_IGN, 0);
+}
+
+static inline long solaris_sigpause(int sig)
+{
+ printk ("Need to support solaris sigpause\n");
+ return -ENOSYS;
+}
+
+asmlinkage long solaris_sigfunc(int sig, u32 arg)
+{
+ int func = sig & ~0xff;
+
+ sig = mapsig(sig & 0xff);
+ if (sig < 0) return sig;
+ switch (func) {
+ case 0: return solaris_signal(sig, arg);
+ case 0x100: return solaris_sigset(sig, arg);
+ case 0x200: return solaris_sighold(sig);
+ case 0x400: return solaris_sigrelse(sig);
+ case 0x800: return solaris_sigignore(sig);
+ case 0x1000: return solaris_sigpause(sig);
+ }
+ return -EINVAL;
+}
+
+typedef struct {
+ u32 __sigbits[4];
+} sol_sigset_t;
+
+static inline int mapin(u32 *p, sigset_t *q)
+{
+ int i;
+ u32 x;
+ int sig;
+
+ *q = 0L;
+ x = p[0];
+ for (i = 1; i <= SOLARIS_NSIGNALS; i++) {
+ if (x & 1) {
+ sig = solaris_to_linux_signals[i];
+ if (sig == -1)
+ return -EINVAL;
+ *q |= 1L << (sig - 1);
+ }
+ x >>= 1;
+ if (i == 32)
+ x = p[1];
+ }
+ return 0;
+}
+
+static inline int mapout(sigset_t *q, u32 *p)
+{
+ int i;
+ sigset_t x;
+ int sig;
+
+ p[0] = 0;
+ p[1] = 0;
+ x = *q;
+ for (i = 1; i <= 32; i++, x >>= 1) {
+ if (x & 1) {
+ sig = linux_to_solaris_signals[i];
+ if (sig == -1)
+ return -EINVAL;
+ if (sig > 32)
+ p[1] |= 1L << (sig - 33);
+ else
+ p[0] |= 1L << (sig - 1);
+ }
+ }
+ return 0;
+
+}
+
+asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out)
+{
+ sigset_t in_s, *ins, out_s, *outs;
+ unsigned long old_fs = get_fs();
+ int ret;
+ int (*sys_sigprocmask)(int,sigset_t *,sigset_t *) =
+ (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask);
+
+ ins = NULL; outs = NULL;
+ if (in) {
+ u32 tmp[2];
+
+ if (copy_from_user (tmp, (sol_sigset_t *)A(in), 2*sizeof(u32)))
+ return -EFAULT;
+ ins = &in_s;
+ if (mapin (tmp, ins)) return -EINVAL;
+ }
+ if (out) outs = &out_s;
+ set_fs (KERNEL_DS);
+ ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how, ins, outs);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (out) {
+ u32 tmp[4];
+
+ tmp[2] = 0; tmp[3] = 0;
+ if (mapout (outs, tmp)) return -EINVAL;
+ if (copy_to_user((sol_sigset_t *)A(out), tmp, 4*sizeof(u32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage long do_sol_sigsuspend(u32 mask)
+{
+ sigset_t s;
+ u32 tmp[2];
+
+ if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32)))
+ return -EFAULT;
+ if (mapin (tmp, &s)) return -EINVAL;
+ return (long)s;
+}
+
+struct sol_sigaction {
+ int sa_flags;
+ u32 sa_handler;
+ u32 sa_mask[4];
+ int sa_resv[2];
+};
+
+asmlinkage int solaris_sigaction(int sig, u32 act, u32 old)
+{
+ u32 tmp, tmp2[4];
+ struct sigaction s, s2;
+ int ret;
+ unsigned long old_fs = get_fs();
+ int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) =
+ (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
+
+ sig = mapsig(sig);
+ if (sig < 0) {
+ /* We cheat a little bit for Solaris only signals */
+ if (old && clear_user((struct sol_sigaction *)A(old), sizeof(struct sol_sigaction)))
+ return -EFAULT;
+ return 0;
+ }
+ if (act) {
+ if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_flags))
+ return -EFAULT;
+ s.sa_flags = 0;
+ if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK;
+ if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART;
+ if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK;
+ if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT;
+ if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP;
+ if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_handler) ||
+ copy_from_user (tmp2, &((struct sol_sigaction *)A(act))->sa_mask, 2*sizeof(u32)))
+ return -EFAULT;
+ s.sa_handler = (__sighandler_t)A(tmp);
+ if (mapin (tmp2, &s.sa_mask)) return -EINVAL;
+ s.sa_restorer = 0;
+ }
+ set_fs(KERNEL_DS);
+ ret = sys_sigaction(sig, act ? &s : NULL, old ? &s2 : NULL);
+ set_fs(old_fs);
+ if (ret) return ret;
+ if (old) {
+ if (mapout (&s2.sa_mask, tmp2)) return -EINVAL;
+ tmp = 0; tmp2[2] = 0; tmp2[3] = 0;
+ if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK;
+ if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART;
+ if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER;
+ if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND;
+ if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP;
+ if (put_user (tmp, &((struct sol_sigaction *)A(old))->sa_flags) ||
+ __put_user ((u32)(long)s2.sa_handler, &((struct sol_sigaction *)A(old))->sa_handler) ||
+ copy_to_user (&((struct sol_sigaction *)A(old))->sa_mask, tmp2, 4*sizeof(u32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int solaris_sigpending(int which, u32 set)
+{
+ sigset_t s;
+ u32 tmp[4];
+ switch (which) {
+ case 1: /* sigpending */
+ lock_kernel();
+ s = current->blocked & current->signal;
+ unlock_kernel();
+ break;
+ case 2: /* sigfillset - I just set signals which have linux equivalents */
+ s = 0x7fffffff;
+ break;
+ default: return -EINVAL;
+ }
+ if (mapout (&s, tmp)) return -EINVAL;
+ tmp[2] = 0; tmp[3] = 0;
+ if (copy_to_user ((u32 *)A(set), tmp, sizeof(tmp)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int solaris_wait(u32 stat_loc)
+{
+ int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
+ (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
+ int ret, status;
+
+ ret = sys_wait4(-1, (unsigned int *)A(stat_loc), WUNTRACED, NULL);
+ if (ret >= 0 && stat_loc) {
+ if (get_user (status, (unsigned int *)A(stat_loc)))
+ return -EFAULT;
+ if (((status - 1) & 0xffff) < 0xff)
+ status = linux_to_solaris_signals[status & 0x7f] & 0x7f;
+ else if ((status & 0xff) == 0x7f)
+ status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f;
+ if (__put_user (status, (unsigned int *)A(stat_loc)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options)
+{
+ int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
+ (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
+ int opts, status, ret;
+
+ switch (idtype) {
+ case 0: /* P_PID */ break;
+ case 1: /* P_PGID */ pid = -pid; break;
+ case 7: /* P_ALL */ pid = -1; break;
+ default: return -EINVAL;
+ }
+ opts = 0;
+ if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED;
+ if (options & SOLARIS_WNOHANG) opts |= WNOHANG;
+ current->state = TASK_RUNNING;
+ ret = sys_wait4(pid, (unsigned int *)A(info), opts, NULL);
+ if (ret < 0) return ret;
+ if (info) {
+ struct sol_siginfo *s = (struct sol_siginfo *)A(info);
+
+ if (get_user (status, (unsigned int *)A(info))) return -EFAULT;
+ __put_user_ret (SOLARIS_SIGCLD, &s->si_signo, -EFAULT);
+ __put_user_ret (ret, &s->_data._proc._pid, -EFAULT);
+ switch (status & 0xff) {
+ case 0: ret = SOLARIS_CLD_EXITED;
+ status = (status >> 8) & 0xff;
+ break;
+ case 0x7f:
+ status = (status >> 8) & 0xff;
+ switch (status) {
+ case SIGSTOP:
+ case SIGTSTP: ret = SOLARIS_CLD_STOPPED;
+ default: ret = SOLARIS_CLD_EXITED;
+ }
+ status = linux_to_solaris_signals[status];
+ break;
+ default:
+ if (status & 0x80) ret = SOLARIS_CLD_DUMPED;
+ else ret = SOLARIS_CLD_KILLED;
+ status = linux_to_solaris_signals[status & 0x7f];
+ break;
+ }
+ __put_user_ret (ret, &s->si_code, -EFAULT);
+ __put_user_ret (status, &s->_data._proc._pdata._cld._status, -EFAULT);
+ }
+ return 0;
+}
+
+extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+
+asmlinkage int solaris_context(struct pt_regs *regs)
+{
+ switch ((unsigned)regs->u_regs[UREG_I0]) {
+ case 0: /* getcontext */
+ return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+ case 1: /* setcontext */
+ return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+ default:
+ return -EINVAL;
+
+ }
+}
+
+asmlinkage int solaris_sigaltstack(u32 ss, u32 oss)
+{
+/* XXX Implement this soon */
+ return 0;
+}
diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h
new file mode 100644
index 000000000..2e948c788
--- /dev/null
+++ b/arch/sparc64/solaris/signal.h
@@ -0,0 +1,109 @@
+/* $Id: signal.h,v 1.2 1997/09/03 12:29:21 jj Exp $
+ * signal.h: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#define SOLARIS_SIGHUP 1
+#define SOLARIS_SIGINT 2
+#define SOLARIS_SIGQUIT 3
+#define SOLARIS_SIGILL 4
+#define SOLARIS_SIGTRAP 5
+#define SOLARIS_SIGIOT 6
+#define SOLARIS_SIGEMT 7
+#define SOLARIS_SIGFPE 8
+#define SOLARIS_SIGKILL 9
+#define SOLARIS_SIGBUS 10
+#define SOLARIS_SIGSEGV 11
+#define SOLARIS_SIGSYS 12
+#define SOLARIS_SIGPIPE 13
+#define SOLARIS_SIGALRM 14
+#define SOLARIS_SIGTERM 15
+#define SOLARIS_SIGUSR1 16
+#define SOLARIS_SIGUSR2 17
+#define SOLARIS_SIGCLD 18
+#define SOLARIS_SIGPWR 19
+#define SOLARIS_SIGWINCH 20
+#define SOLARIS_SIGURG 21
+#define SOLARIS_SIGPOLL 22
+#define SOLARIS_SIGSTOP 23
+#define SOLARIS_SIGTSTP 24
+#define SOLARIS_SIGCONT 25
+#define SOLARIS_SIGTTIN 26
+#define SOLARIS_SIGTTOU 27
+#define SOLARIS_SIGVTALRM 28
+#define SOLARIS_SIGPROF 29
+#define SOLARIS_SIGXCPU 30
+#define SOLARIS_SIGXFSZ 31
+#define SOLARIS_SIGWAITING 32
+#define SOLARIS_SIGLWP 33
+#define SOLARIS_SIGFREEZE 34
+#define SOLARIS_SIGTHAW 35
+#define SOLARIS_SIGCANCEL 36
+#define SOLARIS_SIGRTMIN 37
+#define SOLARIS_SIGRTMAX 44
+#define SOLARIS_NSIGNALS 44
+
+
+#define SOLARIS_SA_ONSTACK 1
+#define SOLARIS_SA_RESETHAND 2
+#define SOLARIS_SA_RESTART 4
+#define SOLARIS_SA_SIGINFO 8
+#define SOLARIS_SA_NODEFER 16
+#define SOLARIS_SA_NOCLDWAIT 0x10000
+#define SOLARIS_SA_NOCLDSTOP 0x20000
+
+struct sol_siginfo {
+ int si_signo;
+ int si_code;
+ int si_errno;
+ union {
+ char pad[128-3*sizeof(int)];
+ struct {
+ s32 _pid;
+ union {
+ struct {
+ s32 _uid;
+ s32 _value;
+ } _kill;
+ struct {
+ s32 _utime;
+ int _status;
+ s32 _stime;
+ } _cld;
+ } _pdata;
+ } _proc;
+ struct { /* SIGSEGV, SIGBUS, SIGILL and SIGFPE */
+ u32 _addr;
+ int _trapno;
+ } _fault;
+ struct { /* SIGPOLL, SIGXFSZ */
+ int _fd;
+ s32 _band;
+ } _file;
+ } _data;
+};
+
+#define SOLARIS_WUNTRACED 0x04
+#define SOLARIS_WNOHANG 0x40
+#define SOLARIS_WEXITED 0x01
+#define SOLARIS_WTRAPPED 0x02
+#define SOLARIS_WSTOPPED WUNTRACED
+#define SOLARIS_WCONTINUED 0x08
+#define SOLARIS_WNOWAIT 0x80
+
+#define SOLARIS_TRAP_BRKPT 1
+#define SOLARIS_TRAP_TRACE 2
+#define SOLARIS_CLD_EXITED 1
+#define SOLARIS_CLD_KILLED 2
+#define SOLARIS_CLD_DUMPED 3
+#define SOLARIS_CLD_TRAPPED 4
+#define SOLARIS_CLD_STOPPED 5
+#define SOLARIS_CLD_CONTINUED 6
+#define SOLARIS_POLL_IN 1
+#define SOLARIS_POLL_OUT 2
+#define SOLARIS_POLL_MSG 3
+#define SOLARIS_POLL_ERR 4
+#define SOLARIS_POLL_PRI 5
+#define SOLARIS_POLL_HUP 6
+
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
new file mode 100644
index 000000000..984b1bdb5
--- /dev/null
+++ b/arch/sparc64/solaris/socksys.c
@@ -0,0 +1,127 @@
+/* $Id: socksys.c,v 1.1 1997/09/03 12:29:27 jj Exp $
+ * socksys.c: /dev/inet/ stuff for Solaris emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg);
+
+static int af_inet_protocols[] = {
+IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
+IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
+0, 0, 0, 0, 0, 0,
+};
+
+static struct file_operations socksys_file_ops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* release */
+};
+
+static int socksys_open(struct inode * inode, struct file * filp)
+{
+ int family, type, protocol, fd;
+ int (*sys_socket)(int,int,int) =
+ (int (*)(int,int,int))SUNOS(97);
+
+ family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
+ switch (family) {
+ case AF_UNIX:
+ type = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case AF_INET:
+ protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf];
+ switch (protocol) {
+ case IPPROTO_TCP: type = SOCK_STREAM; break;
+ case IPPROTO_UDP: type = SOCK_DGRAM; break;
+ default: type = SOCK_RAW; break;
+ }
+ break;
+ default:
+ type = SOCK_RAW;
+ protocol = 0;
+ break;
+ }
+ fd = sys_socket(family, type, protocol);
+ if (fd < 0) return fd;
+ return 0;
+}
+
+static int socksys_release(struct inode * inode, struct file * filp)
+{
+ return 0;
+}
+
+static unsigned int socksys_poll(struct file * filp, poll_table * wait)
+{
+ return 0;
+}
+
+static struct file_operations socksys_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ socksys_open, /* open */
+ socksys_release,/* release */
+};
+
+__initfunc(int
+init_socksys(void))
+{
+ int ret;
+ int (*sys_socket)(int,int,int) =
+ (int (*)(int,int,int))SUNOS(97);
+ int (*sys_close)(unsigned int) =
+ (int (*)(unsigned int))SYS(close);
+
+ ret = register_chrdev (30, "socksys", &socksys_fops);
+ if (ret < 0) {
+ printk ("Couldn't register socksys character device\n");
+ return ret;
+ }
+ ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (ret < 0) {
+ printk ("Couldn't create socket\n");
+ return ret;
+ }
+ socksys_file_ops = *current->files->fd[ret]->f_op;
+ sys_close(ret);
+ socksys_file_ops.poll = socksys_poll;
+ socksys_file_ops.release = socksys_release;
+ return 0;
+}
+
+void
+cleanup_socksys(void)
+{
+ if (unregister_chrdev (30, "socksys"))
+ printk ("Couldn't unregister socksys character device\n");
+}
diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S
new file mode 100644
index 000000000..c425fb721
--- /dev/null
+++ b/arch/sparc64/solaris/systbl.S
@@ -0,0 +1,289 @@
+/* $Id: systbl.S,v 1.5 1997/09/04 15:46:24 jj Exp $
+ * systbl.S: System call entry point table for Solaris compatibility.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <asm/unistd.h>
+
+/* Fall back to sys_call_table32 entry */
+#define CHAIN(name) __NR_##name
+
+/* Pass pt_regs pointer as first argument */
+#define REGS(name) name+1
+
+/* Hack till all be implemented */
+#define solaris_getmsg solaris_unimplemented
+#define solaris_getpmsg solaris_unimplemented
+#define solaris_hrtsys solaris_unimplemented
+#define solaris_msgsys solaris_unimplemented
+#define solaris_putmsg solaris_unimplemented
+#define solaris_putpmsg solaris_unimplemented
+#define solaris_semsys solaris_unimplemented
+
+ .data
+ .align 1024
+ .globl solaris_sys_table
+solaris_sys_table:
+ .word solaris_unimplemented /* nosys 0 */
+ .word CHAIN(exit) /* exit d 1 */
+ .word CHAIN(fork) /* fork 2 */
+ .word CHAIN(read) /* read dpd 3 */
+ .word CHAIN(write) /* write dpd 4 */
+ .word solaris_open /* open soo 5 */
+ .word CHAIN(close) /* close d 6 */
+ .word solaris_wait /* wait xxx 7 */
+ .word CHAIN(creat) /* creat so 8 */
+ .word CHAIN(link) /* link ss 9 */
+ .word CHAIN(unlink) /* unlink s 10 */
+ .word solaris_unimplemented /* exec sxx 11 */
+ .word CHAIN(chdir) /* chdir s 12 */
+ .word CHAIN(time) /* time 13 */
+ .word solaris_mknod /* mknod sox 14 */
+ .word CHAIN(chmod) /* chmod so 15 */
+ .word solaris_chown /* chown sdd 16 */
+ .word solaris_brk /* brk/break x 17 */
+ .word solaris_stat /* stat sp 18 */
+ .word CHAIN(lseek) /* seek/lseek ddd 19 */
+ .word solaris_getpid /* getpid 20 */
+ .word solaris_unimplemented /* mount 21 */
+ .word CHAIN(umount) /* umount s 22 */
+ .word CHAIN(setuid) /* setuid d 23 */
+ .word solaris_getuid /* getuid 24 */
+ .word CHAIN(stime) /* stime d 25 */
+#if 0
+ .word solaris_ptrace /* ptrace xdxx 26 */
+#else
+ .word CHAIN(ptrace) /* ptrace xdxx 26 */
+#endif
+ .word CHAIN(alarm) /* alarm d 27 */
+ .word solaris_fstat /* fstat dp 28 */
+ .word CHAIN(pause) /* pause 29 */
+ .word CHAIN(utime) /* utime xx 30 */
+ .word solaris_unimplemented /* stty 31 */
+ .word solaris_unimplemented /* gtty 32 */
+ .word solaris_access /* access so 33 */
+ .word CHAIN(nice) /* nice d 34 */
+ .word solaris_statfs /* statfs spdd 35 */
+ .word CHAIN(sync) /* sync 36 */
+ .word solaris_kill /* kill dd 37 */
+ .word solaris_fstatfs /* fstatfs dpdd 38 */
+ .word solaris_procids /* pgrpsys ddd 39 */
+ .word solaris_unimplemented /* xenix 40 */
+ .word CHAIN(dup) /* dup d 41 */
+ .word CHAIN(pipe) /* pipe 42 */
+ .word CHAIN(times) /* times p 43 */
+ .word CHAIN(profil) /* prof xxxx 44 */
+ .word solaris_unimplemented /* lock/plock 45 */
+ .word CHAIN(setgid) /* setgid d 46 */
+ .word solaris_getgid /* getgid 47 */
+ .word solaris_sigfunc /* sigfunc xx 48 */
+ .word REGS(solaris_msgsys) /* msgsys dxddd 49 */
+ .word solaris_unimplemented /* syssun/3b 50 */
+ .word CHAIN(acct) /* acct/sysacct x 51 */
+ .word solaris_shmsys /* shmsys ddxo 52 */
+ .word REGS(solaris_semsys) /* semsys dddx 53 */
+ .word solaris_ioctl /* ioctl dxx 54 */
+ .word solaris_unimplemented /* uadmin xxx 55 */
+ .word solaris_unimplemented /* reserved:exch 56 */
+ .word solaris_utssys /* utssys x 57 */
+ .word CHAIN(fsync) /* fsync d 58 */
+ .word CHAIN(execve) /* execv spp 59 */
+ .word CHAIN(umask) /* umask o 60 */
+ .word CHAIN(chroot) /* chroot s 61 */
+ .word solaris_fcntl /* fcntl dxx 62 */
+ .word solaris_ulimit /* ulimit xx 63 */
+ .word solaris_unimplemented /* ? 64 */
+ .word solaris_unimplemented /* ? 65 */
+ .word solaris_unimplemented /* ? 66 */
+ .word solaris_unimplemented /* ? 67 */
+ .word solaris_unimplemented /* ? 68 */
+ .word solaris_unimplemented /* ? 69 */
+ .word solaris_unimplemented /* advfs 70 */
+ .word solaris_unimplemented /* unadvfs 71 */
+ .word solaris_unimplemented /* rmount 72 */
+ .word solaris_unimplemented /* rumount 73 */
+ .word solaris_unimplemented /* rfstart 74 */
+ .word solaris_unimplemented /* ? 75 */
+ .word solaris_unimplemented /* rdebug 76 */
+ .word solaris_unimplemented /* rfstop 77 */
+ .word solaris_unimplemented /* rfsys 78 */
+ .word CHAIN(rmdir) /* rmdir s 79 */
+ .word CHAIN(mkdir) /* mkdir so 80 */
+ .word CHAIN(getdents) /* getdents dxd 81 */
+ .word solaris_unimplemented /* libattach 82 */
+ .word solaris_unimplemented /* libdetach 83 */
+ .word CHAIN(sysfs) /* sysfs dxx 84 */
+ .word REGS(solaris_getmsg) /* getmsg dxxx 85 */
+ .word REGS(solaris_putmsg) /* putmsg dxxd 86 */
+ .word CHAIN(poll) /* poll xdd 87 */
+ .word solaris_lstat /* lstat sp 88 */
+ .word CHAIN(symlink) /* symlink ss 89 */
+ .word CHAIN(readlink) /* readlink spd 90 */
+ .word CHAIN(setgroups) /* setgroups dp 91 */
+ .word CHAIN(getgroups) /* getgroups dp 92 */
+ .word CHAIN(fchmod) /* fchmod do 93 */
+ .word CHAIN(fchown) /* fchown ddd 94 */
+ .word solaris_sigprocmask /* sigprocmask dxx 95 */
+ .word solaris_sigsuspend /* sigsuspend x 96 */
+ .word solaris_sigaltstack /* sigaltstack xx 97 */
+ .word solaris_sigaction /* sigaction dxx 98 */
+ .word solaris_sigpending /* sigpending dd 99 */
+ .word REGS(solaris_context) /* context 100 */
+ .word solaris_unimplemented /* evsys 101 */
+ .word solaris_unimplemented /* evtrapret 102 */
+ .word solaris_statvfs /* statvfs sp 103 */
+ .word solaris_fstatvfs /* fstatvfs dp 104 */
+ .word solaris_unimplemented /* unknown 105 */
+ .word solaris_unimplemented /* nfssys 106 */
+ .word solaris_waitid /* waitid ddxd 107 */
+ .word solaris_unimplemented /* sigsendsys ddd 108 */
+ .word REGS(solaris_hrtsys) /* hrtsys xxx 109 */
+ .word solaris_unimplemented /* acancel dxd 110 */
+ .word solaris_unimplemented /* async 111 */
+ .word solaris_unimplemented /* priocntlsys 112 */
+ .word solaris_pathconf /* pathconf sd 113 */
+ .word solaris_unimplemented /* mincore xdx 114 */
+ .word solaris_mmap /* mmap xxxxdx 115 */
+ .word CHAIN(mprotect) /* mprotect xdx 116 */
+ .word CHAIN(munmap) /* munmap xd 117 */
+ .word solaris_fpathconf /* fpathconf dd 118 */
+ .word CHAIN(fork) /* fork 119 */
+ .word solaris_unimplemented /* fchdir d 120 */
+ .word CHAIN(readv) /* readv dxd 121 */
+ .word CHAIN(writev) /* writev dxd 122 */
+ .word solaris_xstat /* xstat dsx 123 */
+ .word solaris_lxstat /* lxstat dsx 124 */
+ .word solaris_fxstat /* fxstat ddx 125 */
+ .word solaris_xmknod /* xmknod dsox 126 */
+ .word solaris_unimplemented /* syslocal d 127 */
+ .word solaris_unimplemented /* setrlimit 128 */
+ .word solaris_unimplemented /* getrlimit 129 */
+ .word CHAIN(chown) /* lchown sdd 130 */
+ .word solaris_unimplemented /* memcntl 131 */
+ .word solaris_getpmsg /* getpmsg dxxxx 132 */
+ .word solaris_putpmsg /* putpmsg dxxdd 133 */
+ .word CHAIN(rename) /* rename ss 134 */
+ .word solaris_utsname /* uname x 135 */
+ .word solaris_unimplemented /* setegid 136 */
+ .word solaris_sysconf /* sysconfig d 137 */
+ .word solaris_unimplemented /* adjtime 138 */
+ .word solaris_sysinfo /* systeminfo dsd 139 */
+ .word solaris_unimplemented /* ? 140 */
+ .word solaris_unimplemented /* seteuid 141 */
+ .word solaris_unimplemented /* ? 142 */
+ .word solaris_unimplemented /* ? 143 */
+ .word solaris_unimplemented /* secsys dx 144 */
+ .word solaris_unimplemented /* filepriv sdxd 145 */
+ .word solaris_unimplemented /* procpriv dxd 146 */
+ .word solaris_unimplemented /* devstat sdx 147 */
+ .word solaris_unimplemented /* aclipc ddddx 148 */
+ .word solaris_unimplemented /* fdevstat ddx 149 */
+ .word solaris_unimplemented /* flvlfile ddx 150 */
+ .word solaris_unimplemented /* lvlfile sdx 151 */
+ .word solaris_unimplemented /* ? 152 */
+ .word solaris_unimplemented /* fchroot d 153 */
+ .word solaris_unimplemented /* lvlproc dx 154 */
+ .word solaris_unimplemented /* ? 155 */
+ .word CHAIN(gettimeofday) /* gettimeofday xx 156 */
+ .word CHAIN(getitimer) /* getitimer dx 157 */
+ .word CHAIN(setitimer) /* setitimer dxx 158 */
+ .word solaris_unimplemented /* lwp-xxx 159 */
+ .word solaris_unimplemented /* lwp-xxx 160 */
+ .word solaris_unimplemented /* lwp-xxx 161 */
+ .word solaris_unimplemented /* lwp-xxx 162 */
+ .word solaris_unimplemented /* lwp-xxx 163 */
+ .word solaris_unimplemented /* lwp-xxx 164 */
+ .word solaris_unimplemented /* lwp-xxx 165 */
+ .word solaris_unimplemented /* lwp-xxx 166 */
+ .word solaris_unimplemented /* lwp-xxx 167 */
+ .word solaris_unimplemented /* lwp-xxx 168 */
+ .word solaris_unimplemented /* lwp-xxx 169 */
+ .word solaris_unimplemented /* lwp-xxx 170 */
+ .word solaris_unimplemented /* lwp-xxx 171 */
+ .word solaris_unimplemented /* lwp-xxx 172 */
+ .word solaris_pread /* pread dpdd 173 */
+ .word solaris_pwrite /* pwrite dpdd 174 */
+ .word REGS(solaris_llseek) /* llseek dLd 175 */
+ .word solaris_unimplemented /* lwpself 176 */
+ .word solaris_unimplemented /* lwpinfo 177 */
+ .word solaris_unimplemented /* lwpprivate 178 */
+ .word solaris_unimplemented /* processorbind 179 */
+ .word solaris_unimplemented /* processorexbind 180 */
+ .word solaris_unimplemented /* 181 */
+ .word solaris_unimplemented /* sync_mailbox 182 */
+ .word solaris_unimplemented /* prepblock 183 */
+ .word solaris_unimplemented /* block 184 */
+ .word solaris_acl /* acl sddp 185 */
+ .word solaris_unimplemented /* unblock 186 */
+ .word solaris_unimplemented /* cancelblock 187 */
+ .word solaris_unimplemented /* ? 188 */
+ .word solaris_unimplemented /* xxxxx 189 */
+ .word solaris_unimplemented /* xxxxxe 190 */
+ .word solaris_unimplemented /* 191 */
+ .word solaris_unimplemented /* 192 */
+ .word solaris_unimplemented /* 193 */
+ .word solaris_unimplemented /* 194 */
+ .word solaris_unimplemented /* 195 */
+ .word solaris_unimplemented /* 196 */
+ .word solaris_unimplemented /* 197 */
+ .word solaris_unimplemented /* 198 */
+ .word CHAIN(nanosleep) /* nanosleep dd 199 */
+ .word solaris_facl /* facl dddp 200 */
+ .word solaris_unimplemented /* 201 */
+ .word solaris_unimplemented /* 202 */
+ .word solaris_unimplemented /* 203 */
+ .word solaris_unimplemented /* 204 */
+ .word solaris_unimplemented /* 205 */
+ .word solaris_unimplemented /* 206 */
+ .word solaris_unimplemented /* 207 */
+ .word solaris_unimplemented /* 208 */
+ .word solaris_unimplemented /* 209 */
+ .word solaris_unimplemented /* 210 */
+ .word solaris_unimplemented /* 211 */
+ .word solaris_unimplemented /* 212 */
+ .word solaris_unimplemented /* 213 */
+ .word solaris_unimplemented /* 214 */
+ .word solaris_unimplemented /* 215 */
+ .word solaris_unimplemented /* 216 */
+ .word solaris_unimplemented /* 217 */
+ .word solaris_unimplemented /* 218 */
+ .word solaris_unimplemented /* 219 */
+ .word solaris_unimplemented /* 220 */
+ .word solaris_unimplemented /* 221 */
+ .word solaris_unimplemented /* 222 */
+ .word solaris_unimplemented /* 223 */
+ .word solaris_unimplemented /* 224 */
+ .word solaris_unimplemented /* 225 */
+ .word solaris_unimplemented /* 226 */
+ .word solaris_unimplemented /* 227 */
+ .word solaris_unimplemented /* 228 */
+ .word solaris_unimplemented /* 229 */
+ .word solaris_unimplemented /* 230 */
+ .word solaris_unimplemented /* 231 */
+ .word solaris_unimplemented /* 232 */
+ .word solaris_unimplemented /* 233 */
+ .word solaris_unimplemented /* 234 */
+ .word solaris_unimplemented /* 235 */
+ .word solaris_unimplemented /* 236 */
+ .word solaris_unimplemented /* 237 */
+ .word solaris_unimplemented /* 238 */
+ .word solaris_unimplemented /* 239 */
+ .word solaris_unimplemented /* 240 */
+ .word solaris_unimplemented /* 241 */
+ .word solaris_unimplemented /* 242 */
+ .word solaris_unimplemented /* 243 */
+ .word solaris_unimplemented /* 244 */
+ .word solaris_unimplemented /* 245 */
+ .word solaris_unimplemented /* 246 */
+ .word solaris_unimplemented /* 247 */
+ .word solaris_unimplemented /* 248 */
+ .word solaris_unimplemented /* 249 */
+ .word solaris_unimplemented /* 250 */
+ .word solaris_unimplemented /* 251 */
+ .word solaris_unimplemented /* 252 */
+ .word solaris_unimplemented /* 253 */
+ .word solaris_unimplemented /* 254 */
+ .word solaris_unimplemented /* 255 */
+
diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds
index eac8314ca..661acc098 100644
--- a/arch/sparc64/vmlinux.lds
+++ b/arch/sparc64/vmlinux.lds
@@ -52,12 +52,14 @@ SECTIONS
. += 8192;
empty_bad_pte_table = .;
. += 8192;
+ empty_bad_page = .;
+ . += 8192;
+ . += 0x40;
empty_null_pmd_table = .;
. += 8192;
+ . += 0x40;
empty_null_pte_table = .;
. += 8192;
- empty_bad_page = .;
- . += 8192;
}
_end = . ;
PROVIDE (end = .);