diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /arch/m68k/kernel | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r-- | arch/m68k/kernel/Makefile | 11 | ||||
-rw-r--r-- | arch/m68k/kernel/bios32.c | 20 | ||||
-rw-r--r-- | arch/m68k/kernel/entry.S | 163 | ||||
-rw-r--r-- | arch/m68k/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/m68k/kernel/ints.c | 12 | ||||
-rw-r--r-- | arch/m68k/kernel/kgdb.c | 168 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_defs.c | 37 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_defs.h | 36 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_ksyms.c | 9 | ||||
-rw-r--r-- | arch/m68k/kernel/process.c | 129 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace.c | 42 | ||||
-rw-r--r-- | arch/m68k/kernel/semaphore.c | 129 | ||||
-rw-r--r-- | arch/m68k/kernel/setup.c | 54 | ||||
-rw-r--r-- | arch/m68k/kernel/signal.c | 104 | ||||
-rw-r--r-- | arch/m68k/kernel/sun3-head.S | 102 | ||||
-rw-r--r-- | arch/m68k/kernel/traps.c | 283 |
16 files changed, 965 insertions, 342 deletions
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 280a5b450..146fcb69b 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -10,11 +10,16 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o +ifndef CONFIG_SUN3 all: head.o kernel.o +else +all: sun3-head.o kernel.o +endif + O_TARGET := kernel.o O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ - setup.o sys_m68k.o time.o -OX_OBJS := m68k_ksyms.o + sys_m68k.o time.o semaphore.o +OX_OBJS := setup.o m68k_ksyms.o ifdef CONFIG_KGDB O_OBJS += kgdb.o @@ -26,6 +31,8 @@ endif head.o: head.S m68k_defs.h +sun3-head.o: sun3-head.S m68k_defs.h + m68k_defs.h: m68k_defs.c m68k_defs.head rm -f m68k_defs.d SUNPRO_DEPENDENCIES="m68k_defs.d m68k_defs.h" \ diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c index b1322261a..55b762bbd 100644 --- a/arch/m68k/kernel/bios32.c +++ b/arch/m68k/kernel/bios32.c @@ -240,7 +240,7 @@ static unsigned int mem_base = FIRST_MEM_ADDR; /* Skip first 32M. */ * accesses. */ -__initfunc(static void disable_dev(struct pci_dev *dev)) +static void __init disable_dev(struct pci_dev *dev) { struct pci_bus *bus; unsigned short cmd; @@ -263,8 +263,8 @@ __initfunc(static void disable_dev(struct pci_dev *dev)) #define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2) -__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base, - unsigned long pci_io_base)) +static void __init layout_dev(struct pci_dev *dev, unsigned long pci_mem_base, + unsigned long pci_io_base) { struct pci_bus *bus; unsigned short cmd; @@ -400,8 +400,8 @@ __initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_bas bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); } -__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base, - unsigned long pci_io_base)) +static void __init layout_bus(struct pci_bus *bus, unsigned long pci_mem_base, + unsigned long pci_io_base) { struct pci_dev *dev; @@ -512,7 +512,7 @@ int pcibios_present(void) return 0; } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); @@ -531,7 +531,7 @@ __initfunc(void pcibios_init(void)) * of the PCI cards. */ -__initfunc(static inline void hades_fixup(void)) +static inline void __init hades_fixup(void) { char irq_tab[4] = { IRQ_TT_MFP_IO0, /* Slot 0. */ @@ -560,7 +560,7 @@ __initfunc(static inline void hades_fixup(void)) } } -__initfunc(void pcibios_fixup(void)) +void __init pcibios_fixup(void) { #if PCI_MODIFY unsigned long orig_mem_base, orig_io_base; @@ -587,11 +587,11 @@ __initfunc(void pcibios_fixup(void)) hades_fixup(); } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 61482c3a8..21acaa218 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -67,11 +67,21 @@ ENTRY(trap) ENTRY(reschedule) | save top of frame - movel %sp,%curptr@(TASK_TSS+TSS_ESP0) + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) + | After a fork we jump here directly from resume, + | so that %d1 contains the previous task + | Theoretically only needed on SMP, but let's watch + | what happens in schedule_tail() in future... +ENTRY(ret_from_fork) + movel %d1,%sp@- + jsr SYMBOL_NAME(schedule_tail) + addql #4,%sp + jra SYMBOL_NAME(ret_from_exception) + badsys: movel #-ENOSYS,PT_D0(%sp) jra SYMBOL_NAME(ret_from_exception) @@ -100,7 +110,7 @@ ENTRY(system_call) GET_CURRENT(%d0) | save top of frame - movel %sp,%curptr@(TASK_TSS+TSS_ESP0) + movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) cmpl #NR_syscalls,%d2 jcc badsys @@ -118,8 +128,10 @@ SYMBOL_NAME_LABEL(ret_from_exception) andw #ALLOWINT,%sr tstl %curptr@(TASK_NEEDRESCHED) jne SYMBOL_NAME(reschedule) +#if 0 cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals jeq 2f +#endif | check for delayed trace bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF) jne do_delayed_trace @@ -152,6 +164,36 @@ do_delayed_trace: addql #4,%sp jra 5b + +#if 0 +#if CONFIG_AMIGA +SYMBOL_NAME_LABEL(ami_inthandler) + addql #1,SYMBOL_NAME(local_irq_count) + SAVE_ALL_INT + GET_CURRENT(%d0) + + bfextu %sp@(PT_VECTOR){#4,#12},%d0 + movel %d0,%a0 + addql #1,%a0@(SYMBOL_NAME(kstat)+STAT_IRQ-VECOFF(VEC_SPUR)) + movel %a0@(SYMBOL_NAME(autoirq_list)-VECOFF(VEC_SPUR)),%a0 + +| amiga vector int handler get the req mask instead of irq vector + lea CUSTOMBASE,%a1 + movew %a1@(C_INTREQR),%d0 + andw %a1@(C_INTENAR),%d0 + +| prepare stack (push frame pointer, dev_id & req mask) + pea %sp@ + movel %a0@(IRQ_DEVID),%sp@- + movel %d0,%sp@- + pea %pc@(SYMBOL_NAME(ret_from_interrupt):w) + jbra @(IRQ_HANDLER,%a0)@(0) + +ENTRY(nmi_handler) + rte +#endif +#endif + /* ** This is the main interrupt handler, responsible for calling process_int() */ @@ -171,7 +213,7 @@ SYMBOL_NAME_LABEL(inthandler) jbeq 1f jbsr SYMBOL_NAME(floppy_hardint) jbra 3f -1: +1: #endif jbsr SYMBOL_NAME(process_int)| process the IRQ 3: addql #8,%sp | pop parameters off stack @@ -179,7 +221,7 @@ SYMBOL_NAME_LABEL(inthandler) SYMBOL_NAME_LABEL(ret_from_interrupt) subql #1,SYMBOL_NAME(local_irq_count) jeq 1f -2: +2: RESTORE_ALL 1: #if 1 @@ -265,25 +307,30 @@ SYMBOL_NAME_LABEL(resume) */ /* save sr */ - movew %sr,%a0@(TASK_TSS+TSS_SR) + movew %sr,%a0@(TASK_THREAD+THREAD_SR) /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ movec %sfc,%d0 - movew %d0,%a0@(TASK_TSS+TSS_FS) + movew %d0,%a0@(TASK_THREAD+THREAD_FS) /* save usp */ /* it is better to use a movel here instead of a movew 8*) */ movec %usp,%d0 - movel %d0,%a0@(TASK_TSS+TSS_USP) + movel %d0,%a0@(TASK_THREAD+THREAD_USP) /* save non-scratch registers on stack */ SAVE_SWITCH_STACK /* save current kernel stack pointer */ - movel %sp,%a0@(TASK_TSS+TSS_KSP) + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save floating point context */ - fsave %a0@(TASK_TSS+TSS_FPSTATE) +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + tstl SYMBOL_NAME(m68k_fputype) + jeq 3f +#endif + fsave %a0@(TASK_THREAD+THREAD_FPSTATE) #if defined(CONFIG_M68060) #if !defined(CPU_M68060_ONLY) @@ -291,127 +338,71 @@ SYMBOL_NAME_LABEL(resume) beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ - tstb %a0@(TASK_TSS+TSS_FPSTATE+2) + tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2) jeq 3f #if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ #if !defined(CPU_M68060_ONLY) -1: tstb %a0@(TASK_TSS+TSS_FPSTATE) +1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) jeq 3f #endif -2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG) - fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL) +2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) + fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL) 3: +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* Return previous task in %d1 */ movel %curptr,%d1 /* switch to new task (a1 contains new task) */ movel %a1,%curptr - /* Skip address space switching if they are the same. */ - movel %a0@(TASK_MM),%d0 - cmpl %a1@(TASK_MM),%d0 + /* restore floating point context */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + tstl SYMBOL_NAME(m68k_fputype) jeq 4f - -#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) - /* 68040 or 68060 ? */ - tstl SYMBOL_NAME(m68k_is040or060) - bnes 1f #endif -#if defined(CPU_M68020_OR_M68030) - /* - * switch address space - */ - - /* flush MC68030/MC68020 caches (they are virtually addressed) */ - movec %cacr,%d0 - oriw #LFLUSH_I_AND_D,%d0 - movec %d0,%cacr - - /* switch the root pointer */ -#ifdef CPU_M68030_ONLY - .chip 68030 - pmovefd %a1@(TASK_TSS+TSS_CRP),%crp - .chip 68k - pflush #0,#4 -#else - pmove %a1@(TASK_TSS+TSS_CRP),%crp -#endif -#endif - -#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) - jra 2f /* skip m68040 stuff */ -1: -#endif -#if defined(CPU_M68040_OR_M68060) - /* - * switch address space - */ - .chip 68040 - - /* flush address translation cache (user entries) */ - pflushan - - /* switch the root pointer */ - movel %a1@(TASK_TSS+TSS_CRP+4),%d0 - movec %d0,%urp - -#if defined (CONFIG_M68060) - /* is it a '060 ? */ -#if !defined(CPU_M68060_ONLY) - btst #3,SYMBOL_NAME(m68k_cputype)+3 - beqs 2f -#endif - /* clear user entries in the branch cache */ - movec %cacr,%d0 - orl #0x00200000,%d0 - movec %d0,%cacr -#endif /* CONFIG_M68060 */ - .chip 68k -#endif /* CPU_M68040_OR_M68060 */ -2: -4: - /* restore floating point context */ - #if defined(CONFIG_M68060) #if !defined(CPU_M68060_ONLY) btst #3,SYMBOL_NAME(m68k_cputype)+3 beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ - tstb %a1@(TASK_TSS+TSS_FPSTATE+2) + tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2) jeq 3f #if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ #if !defined(CPU_M68060_ONLY) -1: tstb %a1@(TASK_TSS+TSS_FPSTATE) +1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) jeq 3f #endif -2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7 - fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar -3: frestore %a1@(TASK_TSS+TSS_FPSTATE) +2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 + fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar +3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) +4: +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* restore the kernel stack pointer */ - movel %a1@(TASK_TSS+TSS_KSP),%sp + movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore non-scratch registers */ RESTORE_SWITCH_STACK /* restore user stack pointer */ - movel %a1@(TASK_TSS+TSS_USP),%a0 + movel %a1@(TASK_THREAD+THREAD_USP),%a0 movel %a0,%usp /* restore fs (sfc,%dfc) */ - movew %a1@(TASK_TSS+TSS_FS),%a0 + movew %a1@(TASK_THREAD+THREAD_FS),%a0 movec %a0,%sfc movec %a0,%dfc /* restore status register */ - movew %a1@(TASK_TSS+TSS_SR),%sr + movew %a1@(TASK_THREAD+THREAD_SR),%sr rts @@ -530,7 +521,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ .long SYMBOL_NAME(sys_vhangup) - .long SYMBOL_NAME(sys_idle) + .long SYMBOL_NAME(sys_ni_syscall) /* obsolete idle() syscall */ .long SYMBOL_NAME(sys_ni_syscall) /* vm86old for i386 */ .long SYMBOL_NAME(sys_wait4) .long SYMBOL_NAME(sys_swapoff) /* 115 */ diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 361b10cb6..49285b86d 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -503,10 +503,18 @@ func_define putn,1 .macro puts string #if defined(CONSOLE) || defined(SERIAL_DEBUG) +/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */ +#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB) + bra 1f +#endif __INITDATA .Lstr\@: .string "\string" __FINIT +#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB) + .align 2 +1: +#endif pea %pc@(.Lstr\@) func_call puts addql #4,%sp diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 31931a920..9dc6427e6 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -86,14 +86,14 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; * the IRQ handling routines. */ -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { int i; for (i = 0; i < SYS_IRQS; i++) { if (mach_default_handler) irq_list[i].handler = (*mach_default_handler)[i]; - irq_list[i].flags = IRQ_FLG_STD; + irq_list[i].flags = 0; irq_list[i].dev_id = NULL; irq_list[i].devname = default_names[i]; } @@ -144,6 +144,7 @@ int sys_request_irq(unsigned int irq, return -ENXIO; } +#if 0 if (!(irq_list[irq].flags & IRQ_FLG_STD)) { if (irq_list[irq].flags & IRQ_FLG_LOCK) { printk("%s: IRQ %d from %s is not replaceable\n", @@ -156,6 +157,8 @@ int sys_request_irq(unsigned int irq, return -EBUSY; } } +#endif + irq_list[irq].handler = handler; irq_list[irq].flags = flags; irq_list[irq].dev_id = dev_id; @@ -175,7 +178,7 @@ void sys_free_irq(unsigned int irq, void *dev_id) __FUNCTION__, irq, irq_list[irq].devname); irq_list[irq].handler = (*mach_default_handler)[irq]; - irq_list[irq].flags = IRQ_FLG_STD; + irq_list[irq].flags = 0; irq_list[irq].dev_id = NULL; irq_list[irq].devname = default_names[irq]; } @@ -250,9 +253,6 @@ int get_irq_list(char *buf) for (i = 0; i < SYS_IRQS; i++) { len += sprintf(buf+len, "auto %2d: %10u ", i, i ? kstat.irqs[0][i] : num_spurious); - if (irq_list[i].flags & IRQ_FLG_LOCK) - len += sprintf(buf+len, "L "); - else len += sprintf(buf+len, " "); len += sprintf(buf+len, "%s\n", irq_list[i].devname); } diff --git a/arch/m68k/kernel/kgdb.c b/arch/m68k/kernel/kgdb.c index cdbd250cd..be75defdb 100644 --- a/arch/m68k/kernel/kgdb.c +++ b/arch/m68k/kernel/kgdb.c @@ -189,6 +189,11 @@ #include <asm/amigahw.h> #include <asm/amigaints.h> #endif +#ifdef CONFIG_MAC +#include <linux/tty.h> +#include <asm/bootinfo.h> +#include <asm/macints.h> +#endif #undef DEBUG @@ -239,6 +244,15 @@ static unsigned char atari_scc_intr( void ); extern int amiga_ser_out( unsigned char c ); extern unsigned char amiga_ser_in( void ); #endif +#ifdef CONFIG_MAC +static unsigned char mac_scca_in( void ); +static unsigned char mac_scca_out( unsigned char c ); +static unsigned char mac_scca_intr( void ); +static unsigned char mac_sccb_in( void ); +static unsigned char mac_sccb_out( unsigned char c); +static unsigned char mac_sccb_intr( void ); +extern void mac_init_scc_port( int cflag, int port ); +#endif /************************* End of Prototypes **************************/ @@ -668,6 +682,31 @@ void kgdb_init(void) } #endif +#ifdef CONFIG_MAC + if (MACH_IS_MAC) { + if (!strcmp( m68k_debug_device, "ser" ) || + !strcmp( m68k_debug_device, "ser1" )) { + mac_init_scc_port( B9600|CS8, 0 ); + serial_in = mac_scca_in; + serial_out = mac_scca_out; + serial_intr = mac_scca_intr; + } else if (!strcmp( m68k_debug_device, "ser2" )) { + mac_init_scc_port( B9600|CS8, 1 ); + serial_in = mac_sccb_in; + serial_out = mac_sccb_out; + serial_intr = mac_sccb_intr; + } + } + if (!serial_in || !serial_out) { + if (*m68k_debug_device) + printk( "kgdb_init failed: no valid serial device!\n" ); + else + printk( "kgdb not enabled\n" ); + return; + } + request_irq(4, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL); +#endif + #ifdef CONFIG_ATARI if (!serial_in || !serial_out) { if (*m68k_debug_device) @@ -781,8 +820,15 @@ __asm__ /* copy format/vector word */ " movew %a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* set stack to CPU frame */ " addl #"FRAMEOFF_SR",%a0\n" @@ -801,8 +847,15 @@ __asm__ /* after return, first restore FPU registers */ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %a0@("GDBOFF_FP0"),%fp0-%fp7\n" " fmoveml %a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* set new stack pointer */ " movel %a0@("GDBOFF_A7"),%sp\n" " clrw %sp@-\n" /* fake format $0 frame */ @@ -849,8 +902,15 @@ __asm__ /* fake format 0 and vector 1 (translated to SIGINT) */ " movew #4,%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_M68KFPU_EMU_ONLY +#ifdef CONFIG_M68KFPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_M68KFPU_EMU_ONLY */ /* pop off the CPU stack frame */ " addql #8,%sp\n" " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */ @@ -1192,3 +1252,111 @@ static unsigned char atari_scc_intr( void ) } #endif + +/* -------------------- Macintosh serial I/O -------------------- */ + +#ifdef CONFIG_MAC + +struct SCC + { + u_char cha_b_ctrl; + u_char char_dummy1; + u_char cha_a_ctrl; + u_char char_dummy2; + u_char cha_b_data; + u_char char_dummy3; + u_char cha_a_data; + }; + +#define scc (*((volatile struct SCC*)mac_bi_data.sccbase)) + +#define uSEC 1 +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 60*uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) + +static unsigned char mac_sccb_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_b_data = c; +} + +static unsigned char mac_scca_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_a_data = c; +} + +static unsigned char mac_sccb_in( void ) +{ + do { + LONG_DELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_b_data ); +} + +static unsigned char mac_scca_in( void ) + +{ + do { + LONG_DELAY(); + } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_a_data ); +} + +static unsigned char mac_sccb_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_b_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_b_ctrl; + LONG_DELAY(); + c = scc.cha_b_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_b_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); + return( c ); +} + +static unsigned char mac_scca_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_a_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_a_ctrl; + LONG_DELAY(); + c = scc.cha_a_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_a_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_a_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); + return( c ); +} + +#endif diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c index e2e6715e7..47cffcfa9 100644 --- a/arch/m68k/kernel/m68k_defs.c +++ b/arch/m68k/kernel/m68k_defs.c @@ -26,25 +26,34 @@ int main(void) DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending)); DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched)); - DEFINE(TASK_TSS, offsetof(struct task_struct, tss)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); /* offsets into the thread struct */ - DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp)); - DEFINE(TSS_USP, offsetof(struct thread_struct, usp)); - DEFINE(TSS_SR, offsetof(struct thread_struct, sr)); - DEFINE(TSS_FS, offsetof(struct thread_struct, fs)); - DEFINE(TSS_CRP, offsetof(struct thread_struct, crp)); - DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0)); - DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp)); - DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl)); - DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate)); + DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); + DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); + DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); + DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); + DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); + DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); + DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); + DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); /* offsets into the pt_regs */ DEFINE(PT_D0, offsetof(struct pt_regs, d0)); DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); + DEFINE(PT_D1, offsetof(struct pt_regs, d1)); + DEFINE(PT_D2, offsetof(struct pt_regs, d2)); + DEFINE(PT_D3, offsetof(struct pt_regs, d3)); + DEFINE(PT_D4, offsetof(struct pt_regs, d4)); + DEFINE(PT_D5, offsetof(struct pt_regs, d5)); + DEFINE(PT_A0, offsetof(struct pt_regs, a0)); + DEFINE(PT_A1, offsetof(struct pt_regs, a1)); + DEFINE(PT_A2, offsetof(struct pt_regs, a2)); + DEFINE(PT_PC, offsetof(struct pt_regs, pc)); DEFINE(PT_SR, offsetof(struct pt_regs, sr)); - /* bitfields are a bit difficult */ DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); @@ -69,6 +78,12 @@ int main(void) DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data)); DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref)); + /* signal defines */ + DEFINE(SIGSEGV, SIGSEGV); + DEFINE(SEGV_MAPERR, SEGV_MAPERR); + DEFINE(SIGTRAP, SIGTRAP); + DEFINE(TRAP_TRACE, TRAP_TRACE); + /* offsets into the custom struct */ DEFINE(CUSTOMBASE, &custom); DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h index 4926a6dad..374e56e27 100644 --- a/arch/m68k/kernel/m68k_defs.h +++ b/arch/m68k/kernel/m68k_defs.h @@ -7,19 +7,29 @@ #define TASK_FLAGS 4 #define TASK_SIGPENDING 8 #define TASK_NEEDRESCHED 20 -#define TASK_TSS 470 -#define TASK_MM 622 -#define TSS_KSP 0 -#define TSS_USP 4 -#define TSS_SR 8 -#define TSS_FS 10 -#define TSS_CRP 12 -#define TSS_ESP0 20 -#define TSS_FPREG 24 -#define TSS_FPCNTL 120 -#define TSS_FPSTATE 132 +#define TASK_THREAD 482 +#define TASK_MM 634 +#define TASK_ACTIVE_MM 638 +#define THREAD_KSP 0 +#define THREAD_USP 4 +#define THREAD_SR 8 +#define THREAD_FS 10 +#define THREAD_CRP 12 +#define THREAD_ESP0 20 +#define THREAD_FPREG 24 +#define THREAD_FPCNTL 120 +#define THREAD_FPSTATE 132 #define PT_D0 32 #define PT_ORIG_D0 36 +#define PT_D1 0 +#define PT_D2 4 +#define PT_D3 8 +#define PT_D4 12 +#define PT_D5 16 +#define PT_A0 20 +#define PT_A1 24 +#define PT_A2 28 +#define PT_PC 46 #define PT_SR 44 #define PT_VECTOR 50 #define IRQ_HANDLER 0 @@ -35,6 +45,10 @@ #define FBCON_FONT_DESC_HEIGHT 12 #define FBCON_FONT_DESC_DATA 16 #define FBCON_FONT_DESC_PREF 20 +#define SIGSEGV 11 +#define SEGV_MAPERR 1 +#define SIGTRAP 5 +#define TRAP_TRACE 2 #define CUSTOMBASE -2132807680 #define C_INTENAR 28 #define C_INTREQR 30 diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 5aae5953c..64af7cf7c 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -38,11 +38,14 @@ EXPORT_SYMBOL(mm_vtop); EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); #endif -EXPORT_SYMBOL(mm_vtop_fallback); EXPORT_SYMBOL(m68k_realnum_memory); EXPORT_SYMBOL(m68k_memory); +#ifndef CONFIG_SUN3 +EXPORT_SYMBOL(mm_vtop_fallback); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(kernel_set_cachemode); +#endif EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); @@ -53,10 +56,7 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(kernel_set_cachemode); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(register_serial); -EXPORT_SYMBOL(unregister_serial); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -69,6 +69,7 @@ EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 97f3bd151..ba94860f6 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -40,49 +40,64 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); union task_union init_task_union - __attribute__((section("init_task"), aligned(2*PAGE_SIZE))) - = { task: INIT_TASK }; +__attribute__((section("init_task"), aligned(KTHREAD_SIZE))) + = { task: INIT_TASK(init_task_union.task) }; + +asmlinkage void ret_from_fork(void); -asmlinkage void ret_from_exception(void); /* * The idle loop on an m68k.. */ -asmlinkage int sys_idle(void) +static void default_idle(void) { - if (current->pid != 0) - return -EPERM; - - /* endless idle loop with no priority at all */ - current->priority = 0; - current->counter = -100; - for (;;) { + while(1) { if (!current->need_resched) -#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) +#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES) /* block out HSYNC on the atari (falcon) */ __asm__("stop #0x2200" : : : "cc"); -#else /* portable version */ +#else __asm__("stop #0x2000" : : : "cc"); -#endif /* machine compilation types */ +#endif schedule(); check_pgt_cache(); } } +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; + idle(); +} + void machine_restart(char * __unused) { if (mach_reset) mach_reset(); + for (;;); } void machine_halt(void) { + if (mach_halt) + mach_halt(); + for (;;); } void machine_power_off(void) @@ -90,6 +105,10 @@ void machine_power_off(void) #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) apm_set_power_state(APM_STATE_OFF); #endif + + if (mach_power_off) + mach_power_off(); + for (;;); } void show_regs(struct pt_regs * regs) @@ -127,7 +146,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) "trap #0\n\t" /* Linux/m68k system call */ "tstl %0\n\t" /* child or parent */ "jne 1f\n\t" /* parent - jump */ - "lea %%sp@(-8192),%6\n\t" /* reload current */ + "lea %%sp@(%c7),%6\n\t" /* reload current */ "movel %3,%%sp@-\n\t" /* push argument */ "jsr %4@\n\t" /* call fn */ "movel %0,%%d1\n\t" /* pass exit value */ @@ -136,7 +155,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) "1:" : "=d" (retval) : "0" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current) + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), + "i" (-KTHREAD_SIZE) : "d0", "d2"); pid = retval; } @@ -149,10 +169,11 @@ void flush_thread(void) { unsigned long zero = 0; set_fs(USER_DS); - current->tss.fs = __USER_DS; - asm volatile (".chip 68k/68881\n\t" - "frestore %0@\n\t" - ".chip 68k" : : "a" (&zero)); + current->thread.fs = __USER_DS; + if (!FPU_IS_EMU) + asm volatile (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (&zero)); } /* @@ -192,7 +213,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct switch_stack * childstack, *stack; unsigned long stack_offset, *retp; - stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs); + stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs); childregs = (struct pt_regs *) ((unsigned long) p + stack_offset); *childregs = *regs; @@ -203,26 +224,28 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; - childstack->retpc = (unsigned long) ret_from_exception; + childstack->retpc = (unsigned long)ret_from_fork; - p->tss.usp = usp; - p->tss.ksp = (unsigned long)childstack; + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; /* * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ - p->tss.fs = get_fs().seg; - - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); - - if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2]) - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) - : "memory"); - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0])); + p->thread.fs = get_fs().seg; + + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } return 0; } @@ -231,20 +254,34 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) { - char fpustate[216]; + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) - return 0; + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" :: "m" (fpu->fpcntl[0]) : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" + asm volatile ("fmovemx %/fp0-%/fp7,%0" :: "m" (fpu->fpregs[0]) : "memory"); - return 1; + return 1; } /* diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 86e225362..7db64849d 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -18,6 +18,7 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> +#include <linux/config.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -37,7 +38,7 @@ /* sets the trace bits. */ #define TRACE_BITS 0x8000 -/* Find the stack offset for a register, relative to tss.esp0. */ +/* Find the stack offset for a register, relative to thread.esp0. */ #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) #define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - sizeof(struct switch_stack)) @@ -60,9 +61,9 @@ static inline long get_reg(struct task_struct *task, int regno) unsigned long *addr; if (regno == PT_USP) - addr = &task->tss.usp; + addr = &task->thread.usp; else if (regno < sizeof(regoff)/sizeof(regoff[0])) - addr = (unsigned long *)(task->tss.esp0 + regoff[regno]); + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); else return 0; return *addr; @@ -77,9 +78,9 @@ static inline int put_reg(struct task_struct *task, int regno, unsigned long *addr; if (regno == PT_USP) - addr = &task->tss.usp; + addr = &task->thread.usp; else if (regno < sizeof(regoff)/sizeof(regoff[0])) - addr = (unsigned long *) (task->tss.esp0 + regoff[regno]); + addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); else return -1; *addr = data; @@ -384,10 +385,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) tmp = get_reg(child, addr); if (addr == PT_SR) tmp >>= 16; - } - else if (addr >= 21 && addr < 49) - tmp = child->tss.fp[addr - 21]; - else + } else if (addr >= 21 && addr < 49) { + tmp = child->thread.fp[addr - 21]; +#ifdef CONFIG_M68KFPU_EMU + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#endif + } else goto out; ret = put_user(tmp,(unsigned long *) data); goto out; @@ -423,7 +431,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } if (addr >= 21 && addr < 48) { - child->tss.fp[addr - 21] = data; +#ifdef CONFIG_M68KFPU_EMU + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } +#endif + child->thread.fp[addr - 21] = data; ret = 0; } goto out; @@ -544,7 +562,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_GETFPREGS: { /* Get the child FPU state. */ ret = 0; - if (copy_to_user((void *)data, &child->tss.fp, + if (copy_to_user((void *)data, &child->thread.fp, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; goto out; @@ -552,7 +570,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SETFPREGS: { /* Set the child FPU state. */ ret = 0; - if (copy_from_user(&child->tss.fp, (void *)data, + if (copy_from_user(&child->thread.fp, (void *)data, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; goto out; diff --git a/arch/m68k/kernel/semaphore.c b/arch/m68k/kernel/semaphore.c new file mode 100644 index 000000000..d62b355e1 --- /dev/null +++ b/arch/m68k/kernel/semaphore.c @@ -0,0 +1,129 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in <asm/semaphore-helper.h> + */ + +#include <linux/sched.h> +#include <asm/semaphore-helper.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 39dcd9c15..adafc9879 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -19,6 +19,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -76,6 +77,8 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*); int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); +void (*mach_halt)( void ) = NULL; +void (*mach_power_off)( void ) = NULL; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; @@ -100,6 +103,9 @@ long m68k_serial_console_init(long, long ); #ifdef CONFIG_HEARTBEAT void (*mach_heartbeat) (int) = NULL; #endif +#ifdef CONFIG_M68K_L2_CACHE +void (*mach_l2_flush) (int) = NULL; +#endif extern void base_trap_init(void); @@ -118,7 +124,7 @@ extern int q40_parse_bootinfo(const struct bi_record *); extern void config_amiga(void); extern void config_atari(void); extern void config_mac(void); -extern void config_sun3(void); +extern void config_sun3(unsigned long *, unsigned long *); extern void config_apollo(void); extern void config_mvme147(void); extern void config_mvme16x(void); @@ -127,10 +133,12 @@ extern void config_hp300(void); extern void config_q40(void); extern void config_sun3x(void); -#define MASK_256K 0xfffc0000 +extern void mac_debugging_short (int, short); +extern void mac_debugging_long (int, long); +#define MASK_256K 0xfffc0000 -__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) +static void __init m68k_parse_bootinfo(const struct bi_record *record) { while (record->tag != BI_LAST) { int unknown = 0; @@ -190,8 +198,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) #endif } -__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p) { extern int _etext, _edata, _end; int i; @@ -205,18 +213,27 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, else if (CPU_IS_060) m68k_is040or060 = 6; +#ifndef CONFIG_SUN3 base_trap_init(); +#endif + /* FIXME: m68k_fputype is passed in by Penguin booter, which can + * be confused by software FPU emulation. BEWARE. + * We should really do our own FPU check at startup. + * [what do we do with buggy 68LC040s? if we have problems + * with them, we should add a test to check_bugs() below] */ +#ifndef CONFIG_M68KFPU_EMU_ONLY /* clear the fpu if we have one */ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; asm __volatile__ ("frestore %0" : : "m" (zero)); } +#endif - 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; + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; *cmdline_p = m68k_command_line; memcpy(saved_command_line, *cmdline_p, CL_SIZE); @@ -272,7 +289,7 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, #endif #ifdef CONFIG_SUN3 case MACH_SUN3: - config_sun3(); + config_sun3(memory_start_p, memory_end_p); break; #endif #ifdef CONFIG_APOLLO @@ -321,10 +338,12 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, } #endif +#ifndef CONFIG_SUN3 *memory_start_p = availmem; *memory_end_p = 0; for (i = 0; i < m68k_num_memory; i++) *memory_end_p += m68k_memory[i].size & MASK_256K; +#endif } int get_cpuinfo(char * buffer) @@ -354,6 +373,9 @@ int get_cpuinfo(char * buffer) clockfactor = 0; } +#ifdef CONFIG_M68KFPU_EMU_ONLY + fpu="none(soft float)"; +#else if (m68k_fputype & FPU_68881) fpu = "68881"; else if (m68k_fputype & FPU_68882) @@ -366,6 +388,7 @@ int get_cpuinfo(char * buffer) fpu = "Sun FPA"; else fpu = "none"; +#endif if (m68k_mmutype & MMU_68851) mmu = "68851"; @@ -452,6 +475,9 @@ void unregister_serial(int i) m68k_unregister_serial(i); #endif } +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); + #ifdef CONFIG_SERIAL_CONSOLE long serial_console_init(long kmem_start, long kmem_end) { @@ -461,13 +487,15 @@ long serial_console_init(long kmem_start, long kmem_end) #endif #if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE) return m68k_serial_console_init(kmem_start, kmem_end); +#else + return kmem_start; #endif } #endif #endif #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) -__initfunc(void floppy_setup(char *str, int *ints)) +void __init floppy_setup(char *str, int *ints) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -481,7 +509,7 @@ void floppy_eject(void) #endif /* for "kbd-reset" cmdline param */ -__initfunc(void kbd_reset_setup(char *str, int *ints)) +void __init kbd_reset_setup(char *str, int *ints) { } @@ -496,7 +524,7 @@ void arch_gettod(int *year, int *mon, int *day, int *hour, void check_bugs(void) { -#ifndef CONFIG_FPU_EMU +#ifndef CONFIG_M68KFPU_EMU if (m68k_fputype == 0) { printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index a2b9ce1d4..f35dd94c5 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -14,6 +14,10 @@ * 68060 fixes by Jesper Skov * * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completly ignored for the emulator + * and the internal floating point format is put on stack) */ /* @@ -156,6 +160,9 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss) /* * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. */ struct sigframe @@ -175,9 +182,9 @@ struct rt_sigframe int sig; struct siginfo *pinfo; void *puc; + char retcode[8]; struct siginfo info; struct ucontext uc; - char retcode[8]; }; @@ -187,6 +194,13 @@ static inline int restore_fpu_state(struct sigcontext *sc) { int err = 1; + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { /* Verify the frame format. */ if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) @@ -239,6 +253,18 @@ static inline int rt_restore_fpu_state(struct ucontext *uc) fpregset_t fpregs; int err = 1; + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + &uc->uc_mcontext.fpregs.f_pcr, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) goto out; if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { @@ -478,7 +504,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) struct switch_stack *sw = (struct switch_stack *) &__unused; struct pt_regs *regs = (struct pt_regs *) (sw + 1); unsigned long usp = rdusp(); - struct sigframe *frame = (struct sigframe *)(usp - 24); + struct sigframe *frame = (struct sigframe *)(usp - 4); sigset_t set; int d0; @@ -536,6 +562,13 @@ badframe: static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) { + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); + memcpy(sc->sc_fpregs, current->thread.fp, 24); + return; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -567,6 +600,16 @@ static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) int context_size = CPU_IS_060 ? 8 : 0; int err = 0; + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -677,25 +720,6 @@ static inline void push_cache (unsigned long vaddr) "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (temp) - : "a" (vaddr + 8)); - - temp &= PAGE_MASK; - temp |= (vaddr + 8) & ~PAGE_MASK; - - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else if (CPU_IS_060) { unsigned long temp; @@ -708,18 +732,6 @@ static inline void push_cache (unsigned long vaddr) "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68060\n\t" - "plpar (%0)\n\t" - ".chip 68k" - : "=a" (temp) - : "0" (vaddr + 8)); - __asm__ __volatile__ (".chip 68060\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else { /* @@ -797,11 +809,9 @@ static void setup_frame (int sig, struct k_sigaction *ka, /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* addaw #20,sp */ - err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0)); /* moveq #,d0; trap #0 */ err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), - (long *)(frame->retcode + 4)); + (long *)(frame->retcode)); if (err) goto give_sigsegv; @@ -881,10 +891,10 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* movel #,d0; trap #0 */ - err |= __put_user(0x203c, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2)); - err |= __put_user(0x4e40, (short *)(frame->retcode + 6)); + /* moveq #,d0; notb d0; trap #0 */ + err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), + (long *)(frame->retcode + 0)); + err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); if (err) goto give_sigsegv; @@ -964,11 +974,10 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(current); - } + recalc_sigpending(current); } /* @@ -985,7 +994,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) siginfo_t info; struct k_sigaction *ka; - current->tss.esp0 = (unsigned long) regs; + current->thread.esp0 = (unsigned long) regs; if (!oldset) oldset = ¤t->blocked; @@ -1084,14 +1093,13 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S new file mode 100644 index 000000000..fa17d83a9 --- /dev/null +++ b/arch/m68k/kernel/sun3-head.S @@ -0,0 +1,102 @@ +#include <linux/config.h> +#include <linux/linkage.h> + +#include <asm/page.h> +#include <asm/contregs.h> +#include <asm/sun3-head.h> + +PSL_HIGHIPL = 0x2700 +NBSG = 0x20000 +ICACHE_ONLY = 0x00000009 +CACHES_OFF = 0x00000008 | actually a clear and disable --m +#define MAS_STACK INT_STACK +ROOT_TABLE_SIZE = 128 +PAGESIZE = 8192 + +.globl SYMBOL_NAME(bootup_user_stack) +.globl SYMBOL_NAME(bootup_kernel_stack) +.globl SYMBOL_NAME(pg0) +.globl SYMBOL_NAME(empty_bad_page) +.globl SYMBOL_NAME(empty_bad_page_table) +.globl SYMBOL_NAME(empty_zero_page) +.globl SYMBOL_NAME(swapper_pg_dir) +.globl SYMBOL_NAME(kernel_pmd_table) +.global SYMBOL_NAME(m68k_pgtable_cachemode) +.global SYMBOL_NAME(kpt) +| todo: all these should be in bss! +SYMBOL_NAME(swapper_pg_dir): .skip 0x2000 +SYMBOL_NAME(pg0): .skip 0x2000 +SYMBOL_NAME(empty_bad_page): .skip 0x2000 +SYMBOL_NAME(empty_bad_page_table): .skip 0x2000 +SYMBOL_NAME(kernel_pmd_table): .skip 0x2000 +SYMBOL_NAME(empty_zero_page): .skip 0x2000 + +.globl SYMBOL_NAME(kernel_pg_dir) +.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table) + + .section .head +ENTRY(_stext) +ENTRY(_start) + +/* Firstly, disable interrupts and set up function codes. */ + movew #PSL_HIGHIPL, %sr + moveq #FC_CONTROL, %d0 + movec %d0, %sfc + movec %d0, %dfc + +/* Make sure we're in context zero. */ + moveq #0, %d0 + movsb %d0, AC_CONTEXT + +/* Copy mappings for first megabyte of RAM to address 0xE000000. */ + lea (AC_SEGMAP+0),%a0 + lea (AC_SEGMAP+KERNBASE),%a1 + moveq #(0x140000/NBSG-1),%d0 +1: movsb %a0@,%d1 + movsb %d1,%a1@ + addl #NBSG,%a0 + addl #NBSG,%a1 + dbf %d0,1b + +/* Disable caches and jump to high code. */ + moveq #ICACHE_ONLY,%d0 | Cache disabled until we're ready to enable it + movc %d0, %cacr | is this the right value? (yes --m) + jmp 1f:l + +/* Following code executes at high addresses (0xE000xxx). */ +1: lea SYMBOL_NAME(init_task_union),%a2 | get initial thread... + lea %a2@(KTHREAD_SIZE),%sp | ...and its stack. + +/* copy bootinfo records from the loader to _end */ + lea SYMBOL_NAME(_end), %a1 + lea BI_START, %a0 + /* number of longs to copy */ + movel %a0@, %d0 +1: addl #4, %a0 + movel %a0@, %a1@ + addl #4, %a1 + dbf %d0, 1b + +/* Point MSP at an invalid page to trap if it's used. --m */ + movl #(PAGESIZE),%d0 + movc %d0,%msp + moveq #-1,%d0 + movsb %d0,(AC_SEGMAP+0x0) + + jbsr SYMBOL_NAME(sun3_init) + + jbsr SYMBOL_NAME(start_kernel) + trap #15 + + .data + .even +SYMBOL_NAME_LABEL(kpt) + .long 0 +SYMBOL_NAME_LABEL(availmem) + .long 0 +| todo: remove next two. --m +SYMBOL_NAME_LABEL(is_medusa) + .long 0 +SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) + .long 0 + diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 1f07014b2..e3a9e560b 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -47,6 +47,9 @@ asmlinkage void buserr(void); asmlinkage void trap(void); asmlinkage void inthandler(void); asmlinkage void nmihandler(void); +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpu_emu(void); +#endif e_vector vectors[256] = { 0, 0, buserr, trap, trap, trap, trap, trap, @@ -65,12 +68,21 @@ asm(".text\n" __ALIGN_STR "\n" SYMBOL_NAME_STR(nmihandler) ": rte"); -__initfunc(void base_trap_init(void)) +void __init base_trap_init(void) { +#ifdef CONFIG_SUN3 + /* Keep the keyboard interrupt working with PROM for debugging. --m */ + e_vector *old_vbr; + __asm__ volatile ("movec %%vbr,%1\n\t" + "movec %0,%%vbr" + : "=&r" (old_vbr) : "r" ((void*)vectors)); + vectors[0x1E] = old_vbr[0x1E]; /* Copy int6 vector. */ +#else /* setup the exception vector table */ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); +#endif - if (CPU_IS_040) { + if (CPU_IS_040 && !FPU_IS_EMU) { /* set up FPSP entry points */ asmlinkage void dz_vec(void) asm ("dz"); asmlinkage void inex_vec(void) asm ("inex"); @@ -93,6 +105,12 @@ __initfunc(void base_trap_init(void)) vectors[VEC_FPUNSUP] = unsupp_vec; } if (CPU_IS_060) { + /* set up ISP entry points */ + asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); + + vectors[VEC_UNIMPII] = unimp_vec; + } + if (CPU_IS_060 && !FPU_IS_EMU) { /* set up IFPSP entry points */ asmlinkage void snan_vec(void) asm ("_060_fpsp_snan"); asmlinkage void operr_vec(void) asm ("_060_fpsp_operr"); @@ -104,8 +122,6 @@ __initfunc(void base_trap_init(void)) asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp"); asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd"); - asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); - vectors[VEC_FPNAN] = snan_vec; vectors[VEC_FPOE] = operr_vec; vectors[VEC_FPOVER] = ovfl_vec; @@ -115,14 +131,10 @@ __initfunc(void base_trap_init(void)) vectors[VEC_LINE11] = fline_vec; vectors[VEC_FPUNSUP] = unsupp_vec; vectors[VEC_UNIMPEA] = effadd_vec; - - /* set up ISP entry points */ - - vectors[VEC_UNIMPII] = unimp_vec; } } -__initfunc(void trap_init (void)) +void __init trap_init (void) { int i; @@ -133,16 +145,19 @@ __initfunc(void trap_init (void)) for (i = 64; i < 256; i++) vectors[i] = inthandler; +#ifdef CONFIG_M68KFPU_EMU + if (FPU_IS_EMU) + vectors[VEC_LINE11] = fpu_emu; +#endif + /* if running on an amiga, make the NMI interrupt do nothing */ if (MACH_IS_AMIGA) { vectors[VEC_INT7] = nmihandler; } -} - -void set_evector(int vecnum, void (*handler)(void)) -{ - if (vecnum >= 0 && vecnum <= 256) - vectors[vecnum] = handler; +#ifdef CONFIG_SUN3 + /* Moved from setup_arch() */ + base_trap_init(); +#endif } @@ -152,6 +167,7 @@ static inline void console_verbose(void) console_loglevel = 15; } + static char *vec_names[] = { "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", @@ -174,12 +190,17 @@ static char *vec_names[] = { "MMU CONFIGURATION ERROR" }; +#ifndef CONFIG_SUN3 static char *space_names[] = { "Space 0", "User Data", "User Program", "Space 3", "Space 4", "Super Data", "Super Program", "CPU" }; - - +#else +static char *space_names[] = { + "Space 0", "User Data", "User Program", "Control", + "Space 4", "Super Data", "Super Program", "CPU" + }; +#endif void die_if_kernel(char *,struct pt_regs *,int); asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, @@ -330,6 +351,17 @@ static inline void access_error040 (struct frame *fp) #endif errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | ((ssw & RW_040) ? 0 : 2); +#ifdef CONFIG_FTRACE + { + unsigned long flags; + + save_flags(flags); + cli(); + do_ftrace(0xfa000000 | errorcode); + do_ftrace(mmusr); + restore_flags(flags); + } +#endif do_page_fault (&fp->ptregs, addr, errorcode); } else { printk ("68040 access error, ssw=%x\n", ssw); @@ -363,6 +395,132 @@ static inline void access_error040 (struct frame *fp) } #endif /* CONFIG_M68040 */ +#if defined(CONFIG_SUN3) +#include <asm/sun3mmu.h> + +extern int mmu_emu_handle_fault (unsigned long, int, int); + +/* sun3 version of bus_error030 */ + +extern inline void bus_error030 (struct frame *fp) +{ + unsigned char buserr_type = sun3_get_buserr (); + unsigned long addr, errorcode; + unsigned short ssw = fp->un.fmtb.ssw; + +#if DEBUG + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + ssw & FC ? + fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 + : + fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); +#endif + + /* + * Check if this page should be demand-mapped. This needs to go before + * the testing for a bad kernel-space access (demand-mapping applies + * to kernel accesses too). + */ + + if ((ssw & DF) + && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) + return; + } + + /* Check for kernel-space pagefault (BAD). */ + if (fp->ptregs.sr & PS_S) { + /* kernel fault must be a data fault to user space */ + if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { + // try checking the kernel mappings before surrender + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) + return; + /* instruction fault or kernel data fault! */ + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + fp->ptregs.pc); + if (ssw & DF) { + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + } + printk ("BAD KERNEL BUSERR\n"); + + die_if_kernel("Oops", &fp->ptregs,0); + force_sig(SIGKILL, current); + return; + } + } else { + /* user fault */ + if (!(ssw & (FC | FB)) && !(ssw & DF)) + /* not an instruction fault or data fault! BAD */ + panic ("USER BUSERR w/o instruction or data fault"); + } + + + /* First handle the data fault, if any. */ + if (ssw & DF) { + addr = fp->un.fmtb.daddr; + +// errorcode bit 0: 0 -> no page 1 -> protection fault +// errorcode bit 1: 0 -> read fault 1 -> write fault + +// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault +// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault + + if (buserr_type & SUN3_BUSERR_PROTERR) + errorcode = 0x01; + else if (buserr_type & SUN3_BUSERR_INVALID) + errorcode = 0x00; + else { + printk ("*** unexpected busfault type=%#04x\n", buserr_type); + printk ("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); + die_if_kernel ("Oops", &fp->ptregs, buserr_type); + force_sig (SIGSEGV, current); + return; + } + +//todo: wtf is RM bit? --m + if (!(ssw & RW) || ssw & RM) + errorcode |= 0x02; + + /* Handle page fault. */ + do_page_fault (&fp->ptregs, addr, errorcode); + + /* Retry the data fault now. */ + return; + } + + /* Now handle the instruction fault. */ + + /* Get the fault address. */ + if (fp->ptregs.format == 0xA) + addr = fp->ptregs.pc + 4; + else + addr = fp->un.fmtb.baddr; + if (ssw & FC) + addr -= 2; + + if (buserr_type & SUN3_BUSERR_INVALID) { + if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) + do_page_fault (&fp->ptregs, addr, 0); + } else { +#ifdef DEBUG + printk ("protection fault on insn access (segv).\n"); +#endif + force_sig (SIGSEGV, current); + } +} +#else #if defined(CPU_M68020_OR_M68030) static inline void bus_error030 (struct frame *fp) { @@ -507,44 +665,6 @@ static inline void bus_error030 (struct frame *fp) else asm volatile ("ploadr %1,%0@" : /* no outputs */ : "a" (addr), "d" (ssw)); - -#if 0 - /* If this was a data fault due to an invalid page and a - prefetch is pending on the same page, simulate it (but - only if the page is now valid). Otherwise we'll get an - weird insn access. */ - if ((ssw & RB) && (mmusr & MMU_I)) - { - unsigned long iaddr; - - if ((fp->ptregs.format) == 0xB) - iaddr = fp->un.fmtb.baddr; - else - iaddr = fp->ptregs.pc + 4; - if (((addr ^ iaddr) & PAGE_MASK) == 0) - { - /* We only need to check the ATC as the entry has - already been set up above. */ - asm volatile ("ptestr #1,%1@,#0\n\t" - "pmove %/psr,%0@" - : : "a" (&temp), "a" (iaddr)); - mmusr = temp; -#ifdef DEBUG - printk ("prefetch iaddr=%#lx ssw=%#x mmusr=%#x\n", - iaddr, ssw, mmusr); -#endif - if (!(mmusr & MMU_I)) - { - unsigned short insn; - asm volatile ("movesw %1@,%0" - : "=r" (insn) - : "a" (iaddr)); - fp->un.fmtb.isb = insn; - fp->un.fmtb.ssw &= ~RB; - } - } - } -#endif } /* Now handle the instruction fault. */ @@ -598,43 +718,6 @@ static inline void bus_error030 (struct frame *fp) die_if_kernel("Oops",&fp->ptregs,mmusr); force_sig(SIGSEGV, current); return; - } else { -#if 0 /* stale ATC entry?? Ignore it */ - -#ifdef DEBUG - static volatile long tlong; -#endif - - printk ("weird insn access at %#lx from pc %#lx (ssw is %#x)\n", - addr, fp->ptregs.pc, ssw); - asm volatile ("ptestr #1,%1@,#0\n\t" - "pmove %/psr,%0@" - : /* no outputs */ - : "a" (&temp), "a" (addr)); - mmusr = temp; - - printk ("level 0 mmusr is %#x\n", mmusr); -#ifdef DEBUG - if (m68k_cputype & CPU_68030) { - asm volatile ("pmove %/tt0,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk ("tt0 is %#lx, ", tlong); - asm volatile ("pmove %/tt1,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk ("tt1 is %#lx\n", tlong); - } - -#endif - -#if DEBUG - printk("Unknown SIGSEGV - 3\n"); -#endif - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; -#endif } create_atc_entry: @@ -643,12 +726,13 @@ create_atc_entry: : "a" (addr)); } #endif /* CPU_M68020_OR_M68030 */ +#endif /* !CONFIG_SUN3 */ asmlinkage void buserr_c(struct frame *fp) { /* Only set esp0 if coming from user mode */ if (user_mode(&fp->ptregs)) - current->tss.esp0 = (unsigned long) fp; + current->thread.esp0 = (unsigned long) fp; #if DEBUG printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); @@ -990,3 +1074,16 @@ asmlinkage void fpsp040_die(void) { do_exit(SIGSEGV); } + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif |