diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
commit | d8d9b8f76f22b7a16a83e261e64f89ee611f49df (patch) | |
tree | 3067bc130b80d52808e6390c9fc7fc087ec1e33c /arch | |
parent | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (diff) |
Initial revision
Diffstat (limited to 'arch')
195 files changed, 4970 insertions, 6074 deletions
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index a6ee5a17c..0c3c65d28 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -42,6 +42,13 @@ CONFIG_SYSVIPC=y CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_EM86=y +# CONFIG_PNP_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set # # Floppy, IDE, and other block devices @@ -72,9 +79,10 @@ CONFIG_BLK_DEV_RAM=y # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set CONFIG_INET=y -# CONFIG_IP_FORWARD is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set # # (it is safe to leave these untouched) @@ -133,11 +141,11 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set @@ -155,19 +163,22 @@ CONFIG_NET_ETHERNET=y # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set CONFIG_DE4X5=y # CONFIG_DEC_ELCP is not set # CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_NET_RADIO is not set -# CONFIG_LAPBETHER is not set # CONFIG_SLIP is not set # CONFIG_TR is not set +# CONFIG_LAPBETHER is not set +# CONFIG_X25_ASY is not set # # ISDN subsystem @@ -192,12 +203,16 @@ CONFIG_MSDOS_FS=y CONFIG_PROC_FS=y CONFIG_NFS_FS=y # CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y # CONFIG_SMB_FS is not set CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set # @@ -206,12 +221,8 @@ CONFIG_ISO9660_FS=y CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y -# CONFIG_DIGI is not set -# CONFIG_CYCLADES is not set -# CONFIG_STALDRV is not set -# CONFIG_RISCOM8 is not set -# CONFIG_ESPSERIAL is not set -# CONFIG_PRINTER is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set CONFIG_MOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set @@ -224,7 +235,6 @@ CONFIG_PSMOUSE=y # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set -CONFIG_RTC_ARC=y # # Sound diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index ef582b80e..af26f8996 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -126,7 +126,8 @@ .ent entInt entInt: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entInt br $31,ret_from_sys_call .end entInt @@ -147,7 +148,8 @@ entMM: stq $15,48($30) addq $30,56,$19 /* handle the fault */ - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_page_fault /* reload the registers after the exception code played. */ ldq $9,0($30) @@ -167,7 +169,8 @@ entMM: .ent entArith entArith: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 /* How much of a win is this clockwise? We are, after all, messing up the call/return prefetch stack. -- rth */ lda $27,do_entArith @@ -180,7 +183,8 @@ entArith: .ent entIF entIF: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 lda $27,do_entIF lda $26,ret_from_sys_call jsr $31,($27),do_entIF @@ -221,12 +225,13 @@ kernel_clone: .globl __kernel_thread .ent __kernel_thread __kernel_thread: + ldgp $29,0($27) /* we can be called from a module */ .frame $30, 4*8, $26 subq $30,4*8,$30 stq $10,16($30) stq $9,8($30) stq $26,0($30) - .prologue 0 + .prologue 1 bis $17,$17,$9 /* save fn */ bis $18,$18,$10 /* save arg */ bsr $26,kernel_clone @@ -238,10 +243,9 @@ __kernel_thread: ret $31,($26),1 /* this is in child: look out as we don't have any stack here.. */ 1: bis $9,$9,$27 /* get fn */ - br $29,2f -2: ldgp $29,0($29) + lda $8,0x3fff bis $10,$10,$16 /* get arg */ - ldq $8,current_set + bic $30,$8,$8 /* get current */ jsr $26,($27) bis $0,$0,$16 jsr $26,sys_exit @@ -382,7 +386,8 @@ entUna: stq $29,232($30) stq $30,240($30) stq $31,248($30) - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entUna ldq $0,0($30) ldq $1,8($30) @@ -432,7 +437,8 @@ entUnaUser: stq $14,40($30) stq $15,48($30) bis $31,$30,$19 - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entUnaUser ldq $9,0($30) ldq $10,8($30) @@ -497,7 +503,8 @@ alpha_switch_to: .ent entSys entSys: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 lda $4,NR_SYSCALLS($31) stq $16,SP_OFF+24($30) lda $5,sys_call_table @@ -532,7 +539,7 @@ ret_from_handle_bh: ret_from_reschedule: lda $0,need_resched ldl $2,0($0) - lda $4,init_task + lda $4,init_task_union bne $2,reschedule xor $4,$8,$4 beq $4,restore_all diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 17ca4581a..f76213624 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -23,9 +23,11 @@ _stext: __start: br $27,1f 1: ldgp $29,0($27) - /* We need to get current loaded up with our first task. */ - ldq $8,current_set - /* And then we can start the kernel. */ + /* We need to get current loaded up with our first task... */ + lda $8,init_task_union + /* ... and find our stack ... */ + lda $30,0x4000($8) + /* ... and then we can start the kernel. */ jsr $26,start_kernel halt .end __start @@ -63,22 +65,6 @@ rdusp: .end rdusp .align 3 - .globl tbi - .ent tbi -tbi: - call_pal PAL_tbi - ret ($26) - .end tbi - - .align 3 - .globl imb - .ent imb -imb: - call_pal PAL_imb - ret ($26) - .end imb - - .align 3 .globl rdmces .ent rdmces rdmces: diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 2eb2d51b7..b6c97e726 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -37,6 +37,24 @@ #include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> +#include <asm/pgtable.h> + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ + +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +union task_union init_task_union __attribute__((section("init_task"))) + = { task: INIT_TASK }; /* * No need to acquire the kernel lock, we're entirely local.. @@ -186,7 +204,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, stack_offset = PAGE_SIZE - sizeof(struct pt_regs); if (!(regs->ps & 8)) stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset); + childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p); *childregs = *regs; childregs->r0 = 0; diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 019fb6b95..c388f0b51 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -67,7 +67,7 @@ * | | | * | | v * +================================+ <------------------------- - * task->kernel_stack_page + * task + PAGE_SIZE */ #define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ + (long)&((struct pt_regs *)0)->reg) @@ -107,19 +107,6 @@ static unsigned short regoff[] = { static long zero; - -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -133,7 +120,7 @@ static inline long get_reg(struct task_struct * task, long regno) zero = 0; addr = &zero; } else { - addr = (long *) (task->kernel_stack_page + regoff[regno]); + addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); } return *addr; } @@ -150,7 +137,7 @@ static inline int put_reg(struct task_struct *task, long regno, long data) } else if (regno == 31) { addr = &zero; } else { - addr = (long *) (task->kernel_stack_page + regoff[regno]); + addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); } *addr = data; return 0; @@ -174,7 +161,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -184,7 +171,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -194,7 +181,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -225,7 +212,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -235,7 +222,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -245,12 +232,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -507,7 +494,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; if (request == PTRACE_ATTACH) { ret = -EPERM; diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 0fa1129ee..31a1f21fc 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -21,9 +21,9 @@ #include <linux/tty.h> #include <linux/delay.h> #include <linux/config.h> /* CONFIG_ALPHA_LCA etc */ +#include <linux/ioport.h> #ifdef CONFIG_RTC -#include <linux/ioport.h> #include <linux/timex.h> #endif diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index a7b1e6f2c..a8bc34108 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -97,7 +97,7 @@ good_area: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } - handle_mm_fault(vma, address, cause > 0); + handle_mm_fault(tsk, vma, address, cause > 0); up(&mm->mmap_sem); return; diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 13e8e4ce4..67faa97d4 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -133,7 +133,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) init_task.tss.ptbr = newptbr; init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ init_task.tss.flags = 0; - init_task.kernel_stack_page = INIT_STACK; load_PCB(&init_task.tss); flush_tlb_all(); @@ -182,7 +181,7 @@ void free_initmem (void) atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } - printk ("Freeing unused kernel memory: %dk freed\n", + printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); } diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds index 2a5f00989..0fb2276ea 100644 --- a/arch/alpha/vmlinux.lds +++ b/arch/alpha/vmlinux.lds @@ -5,6 +5,7 @@ SECTIONS . = 0xfffffc0000310000; _text = .; .text : { *(.text) } + .text2 : { *(.text2) } _etext = .; /* Exception table */ @@ -25,9 +26,12 @@ SECTIONS __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } - . = ALIGN(8192); + . = ALIGN(2*8192); /* Align double page for init_task_union */ __init_end = .; + /* The initial task and kernel stack */ + init_task : { *(init_task) } + /* Global data */ _data = .; .rodata : { *(.rodata) } diff --git a/arch/i386/Makefile b/arch/i386/Makefile index c67b8671a..bc4e03029 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -45,7 +45,7 @@ ifdef SMP CFLAGS := $(CFLAGS) -D__SMP__ endif -HEAD := arch/i386/kernel/head.o +HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) @@ -85,7 +85,7 @@ bzdisk: vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zdisk install: vmlinux - @$(MAKEBOOT) install + @$(MAKEBOOT) BOOTIMAGE=bzImage install archclean: @$(MAKEBOOT) clean diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 8507b7081..d09f11283 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -1,12 +1,13 @@ ! -! Display adapter & video mode setup, version 2.10 (11-Nov-96) +! Display adapter & video mode setup, version 2.11 (03-May-97) ! -! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz> +! Copyright (C) 1995 -- 1997 Martin Mares <mj@k332.feld.cvut.cz> ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! -! Enable autodetection of SVGA adapters and modes -#define CONFIG_VIDEO_SVGA +! Enable autodetection of SVGA adapters and modes. If you really need this +! feature, drop me a mail as I think of removing it some day... +#undef CONFIG_VIDEO_SVGA ! Enable autodetection of VESA modes #define CONFIG_VIDEO_VESA @@ -1807,11 +1808,11 @@ listhdr: db 0x0d, 0x0a .ascii "Mode: COLSxROWS:" crlft: db 0x0d, 0x0a, 0 prompt: db 0x0d, 0x0a - .ascii "Enter mode number: " + .ascii "Enter mode number or `scan': " db 0 unknt: .ascii "Unknown mode ID. Try again." db 0 -badmdt: .ascii "You passed an undefined mode number to setup." +badmdt: .ascii "You passed an undefined mode number." db 0x0d, 0x0a, 0 vesaer: .ascii "Error: Scanning of VESA modes failed. Please " .ascii "report to <mj@k332.feld.cvut.cz>." diff --git a/arch/i386/defconfig b/arch/i386/defconfig index e5b5d9f84..a27b6ebce 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -141,6 +141,7 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index e04fb5efb..9491ef562 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -15,7 +15,7 @@ else $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o endif -all: kernel.o head.o +all: kernel.o head.o init_task.o O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \ diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index e128000c3..157e62b2d 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -1,6 +1,8 @@ /* * bios32.c - BIOS32, PCI BIOS functions. * + * $Id: bios32.c,v 1.11 1997/05/07 13:35:21 mj Exp $ + * * Sponsored by * iX Multiuser Multitasking Magazine * Hannover, Germany @@ -52,6 +54,11 @@ * Feb 3, 1997 : Set internal functions to static, save/restore flags * avoid dead locks reading broken PCI BIOS, werner@suse.de * + * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS + * (mj@atrey.karlin.mff.cuni.cz) + * + * May 7, 1997 : Added some missing cli()'s. [mj] + * */ #include <linux/config.h> @@ -158,7 +165,7 @@ static unsigned long bios32_service(unsigned long service) unsigned long entry; /* %edx */ unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%edi)" : "=a" (return_code), "=b" (address), @@ -173,10 +180,10 @@ static unsigned long bios32_service(unsigned long service) case 0: return address + entry; case 0x80: /* Not present */ - printk("bios32_service(%ld) : not present\n", service); + printk("bios32_service(0x%lx) : not present\n", service); return 0; default: /* Shouldn't happen */ - printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n", + printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n", service, return_code); return 0; } @@ -189,7 +196,7 @@ static struct { } pci_indirect = { 0, KERNEL_CS }; -__initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end)) +__initfunc(static int check_pcibios(void)) { unsigned long signature; unsigned char present_status; @@ -201,7 +208,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign if ((pcibios_entry = bios32_service(PCI_SERVICE))) { pci_indirect.address = pcibios_entry | PAGE_OFFSET; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -212,7 +219,7 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "bx", "cx"); - restore_flags(flags); + restore_flags(flags); present_status = (pack >> 16) & 0xff; major_revision = (pack >> 8) & 0xff; @@ -232,9 +239,10 @@ __initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsign if (pcibios_entry) { printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n", major_revision, minor_revision, pcibios_entry); + return 1; } } - return memory_start; + return 0; } @@ -245,7 +253,7 @@ static int pci_bios_find_class (unsigned int class_code, unsigned short index, unsigned long ret; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__ ("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -270,7 +278,7 @@ static int pci_bios_find_device (unsigned short vendor, unsigned short device_id unsigned short ret; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -295,7 +303,7 @@ static int pci_bios_read_config_byte(unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -317,7 +325,7 @@ static int pci_bios_read_config_word (unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -339,7 +347,7 @@ static int pci_bios_read_config_dword (unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -361,7 +369,7 @@ static int pci_bios_write_config_byte (unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -383,7 +391,7 @@ static int pci_bios_write_config_word (unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -405,7 +413,7 @@ static int pci_bios_write_config_dword (unsigned char bus, unsigned long bx = (bus << 8) | device_fn; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -476,7 +484,7 @@ static int pci_direct_find_class (unsigned int class_code, unsigned short index, struct pci_dev *dev; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); for (dev = pci_devices; dev; dev = dev->next) { if (dev->class == class_code) { if (curr == index) { @@ -502,7 +510,7 @@ static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); switch (where & 3) { case 0: *value = inb(0xCFC); @@ -523,7 +531,7 @@ static int pci_conf1_read_config_word (unsigned char bus, { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); if (where & 2) *value = inw(0xCFE); @@ -538,7 +546,7 @@ static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_ { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); restore_flags(flags); @@ -550,7 +558,7 @@ static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_ { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outb(value, 0xCFC); restore_flags(flags); @@ -562,7 +570,7 @@ static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_ { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outw(value, 0xCFC); restore_flags(flags); @@ -574,7 +582,7 @@ static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); restore_flags(flags); @@ -610,7 +618,7 @@ static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inb(IOADDR(device_fn,where)); @@ -626,7 +634,7 @@ static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_f if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inw(IOADDR(device_fn,where)); @@ -642,7 +650,7 @@ static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_ if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inl (IOADDR(device_fn,where)); @@ -656,7 +664,7 @@ static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_ { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outb (value, IOADDR(device_fn,where)); @@ -670,7 +678,7 @@ static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_ { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outw (value, IOADDR(device_fn,where)); @@ -684,7 +692,7 @@ static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device { unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outl (value, IOADDR(device_fn,where)); @@ -716,7 +724,7 @@ __initfunc(static struct pci_access *check_direct_pci(void)) unsigned int tmp; unsigned long flags; - save_flags(flags); + save_flags(flags); cli(); /* * check if configuration type 1 works @@ -912,13 +920,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long bios32_entry = check->fields.entry; printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); bios32_indirect.address = bios32_entry + PAGE_OFFSET; - access_pci = &pci_bios_access; } } } - if (bios32_entry) { - memory_start = check_pcibios (memory_start, memory_end); - } + if (bios32_entry && check_pcibios()) + access_pci = &pci_bios_access; #endif return memory_start; } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 84fe0c7fd..ac67da797 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -110,62 +110,45 @@ ENOSYS = 38 addl $4,%esp; \ iret -#ifdef __SMP__ -/* Get the processor ID multiplied by 4 */ -#define GET_PROCESSOR_OFFSET(reg) \ - movl SYMBOL_NAME(apic_reg), reg; \ - movl 32(reg), reg; \ - shrl $22, reg; \ - andl $0x3C, reg; - -#define GET_CURRENT(reg) \ - GET_PROCESSOR_OFFSET(reg) \ - movl SYMBOL_NAME(current_set)(reg),reg - -#else - #define GET_CURRENT(reg) \ - movl SYMBOL_NAME(current_set),reg - -#endif + movl %esp, reg; \ + andl $-8192, reg; ENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL - GET_CURRENT(%ebx) movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. movl %eax,EFLAGS(%esp) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # - movl %esp,%eax - GET_CURRENT(%edx) - pushl %eax - movl exec_domain(%edx),%edx # Get the execution domain + movl %esp,%ebx + pushl %ebx + andl $-8192,%ebx # GET_CURRENT + movl exec_domain(%ebx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain call *%edx popl %eax jmp ret_from_sys_call + #ifdef __SMP__ ALIGN .globl ret_from_smpfork ret_from_smpfork: + GET_CURRENT(%ebx) btrl $0, SYMBOL_NAME(scheduler_lock) jmp ret_from_sys_call #endif /* __SMP__ */ - ALIGN -handle_bottom_half: - pushl $2f - jmp SYMBOL_NAME(do_bottom_half) - - ALIGN -reschedule: - pushl $ret_from_sys_call - jmp SYMBOL_NAME(schedule) # test +/* + * Return to user mode is not as complex as all this looks, + * but we want the default path for a system call return to + * go as quickly as possible which is why some of this is + * less clear than it otherwise should be. + */ ENTRY(system_call) pushl %eax # save orig_eax @@ -180,16 +163,11 @@ ENTRY(system_call) ALIGN .globl ret_from_sys_call .globl ret_from_intr -ret_from_intr: ret_from_sys_call: - GET_CURRENT(%ebx) movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half -2: movl EFLAGS(%esp),%eax # mix EFLAGS and CS - movb CS(%esp),%al - testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? - je 1f +ret_with_reschedule: cmpl $0,SYMBOL_NAME(need_resched) jne reschedule movl blocked(%ebx),%eax @@ -197,7 +175,6 @@ ret_from_sys_call: notl %eax andl signal(%ebx),%eax jne signal_return -1: RESTORE_ALL ALIGN signal_return: @@ -230,6 +207,30 @@ badsys: movl $-ENOSYS,EAX(%esp) jmp ret_from_sys_call + ALIGN +ret_from_exception: + movl SYMBOL_NAME(bh_mask),%eax + andl SYMBOL_NAME(bh_active),%eax + jne handle_bottom_half + ALIGN +ret_from_intr: + GET_CURRENT(%ebx) + movl EFLAGS(%esp),%eax # mix EFLAGS and CS + movb CS(%esp),%al + testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? + jne ret_with_reschedule + RESTORE_ALL + + ALIGN +handle_bottom_half: + pushl $ret_from_intr + jmp SYMBOL_NAME(do_bottom_half) + + ALIGN +reschedule: + pushl $ret_from_sys_call + jmp SYMBOL_NAME(schedule) # test + ENTRY(divide_error) pushl $0 # no error code @@ -260,7 +261,7 @@ error_code: GET_CURRENT(%ebx) call *%ecx addl $8,%esp - jmp ret_from_sys_call + jmp ret_from_exception ENTRY(coprocessor_error) pushl $0 @@ -271,7 +272,7 @@ ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL GET_CURRENT(%ebx) - pushl $ret_from_sys_call + pushl $ret_from_exception movl %cr0,%eax testl $0x4,%eax # EM (math emulation bit) je SYMBOL_NAME(math_state_restore) diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 2bd095997..a42b87b1b 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -39,19 +39,21 @@ startup_32: jz 1f /* * New page tables may be in 4Mbyte page mode and may - * be using the global pages. + * be using the global pages. + * + * NOTE! We have to correct for the fact that we're + * not yet offset 0xC0000000.. */ +#define cr4_bits mmu_cr4_features-0xC0000000 #ifdef GAS_KNOWS_CR4 movl %cr4,%eax # Turn on 4Mb pages - orl $16+128,%eax + orl cr4_bits,%eax movl %eax,%cr4 #else .byte 0x0f,0x20,0xe0 - orl $16+128,%eax + orl cr4_bits,%eax .byte 0x0f,0x22,0xe0 #endif - movl %eax,%cr3 /* flush TLB as per app note */ - movl %cr0,%eax #endif /* * Setup paging (the tables are already set up, just switch them on) @@ -67,24 +69,16 @@ startup_32: movl $1f,%eax jmp *%eax /* make sure eip is relocated */ 1: + /* Set up the stack pointer */ + lss stack_start,%esp #ifdef __SMP__ orw %bx,%bx jz 1f /* Initial CPU cleans BSS */ -/* - * Set up the stack - */ - movl $(KERNEL_DS),%eax /* walken modif */ - mov %ax,%ss - xorl %eax,%eax - movw %cx, %ax - movl %eax,%esp - addl $0xC0000000, %esp /* shift it to the upper mapping */ pushl $0 popfl jmp checkCPUtype 1: - lss stack_start,%esp #endif __SMP__ /* * Clear BSS first so that there are no surprises... @@ -305,15 +299,53 @@ rp_sidt: jne rp_sidt ret +ENTRY(stack_start) + .long SYMBOL_NAME(init_task_union)+8192 + .long KERNEL_DS + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n" + ALIGN +ignore_int: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + movl $(KERNEL_DS),%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call SYMBOL_NAME(printk) + popl %eax + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +/* + * The interrupt descriptor table has room for 256 idt's + */ + ALIGN +.word 0 +idt_descr: + .word 256*8-1 # idt contains 256 entries + .long SYMBOL_NAME(idt) + + ALIGN +.word 0 +gdt_descr: +#ifdef CONFIG_APM + .word (11+2*NR_TASKS)*8-1 +#else + .word (8+2*NR_TASKS)*8-1 +#endif + .long SYMBOL_NAME(gdt) /* - * page 0 is made non-existent, so that kernel NULL pointer references get - * caught. Thus the swapper page directory has been moved to 0x101000 - * with the introduction of the compressed boot code. Theoretically, - * the original design of overlaying the startup code with the swapper - * page directory is still possible --- it would reduce the size of the kernel - * by 2-3k. This would be a good thing to do at some point..... - * * This is initialized to create a identity-mapping at 0-4M (for bootup * purposes) and another mapping of the 0-4M area at virtual address * 0xC0000000. @@ -471,63 +503,29 @@ ENTRY(empty_bad_page_table) ENTRY(empty_zero_page) .org 0x6000 - -stack_start: - .long SYMBOL_NAME(init_user_stack)+4096 - .long KERNEL_DS - -/* This is the default interrupt "handler" :-) */ -int_msg: - .asciz "Unknown interrupt\n" - ALIGN -ignore_int: - cld - pushl %eax - pushl %ecx - pushl %edx - push %ds - push %es - push %fs - movl $(KERNEL_DS),%eax - mov %ax,%ds - mov %ax,%es - mov %ax,%fs - pushl $int_msg - call SYMBOL_NAME(printk) - popl %eax - pop %fs - pop %es - pop %ds - popl %edx - popl %ecx - popl %eax - iret +ENTRY(this_must_match_init_task) /* - * The interrupt descriptor table has room for 256 idt's + * This starts the data section. Note that the above is all + * in the text section because it has alignment requirements + * that we cannot fulfill any other way. */ - ALIGN -.word 0 -idt_descr: - .word 256*8-1 # idt contains 256 entries - .long SYMBOL_NAME(idt) +.data +ALIGN +/* 256 quadwords - 2048 bytes of idt */ ENTRY(idt) .fill 256,8,0 # idt is uninitialized - ALIGN -.word 0 -gdt_descr: -#ifdef CONFIG_APM - .word (11+2*NR_TASKS)*8-1 -#else - .word (8+2*NR_TASKS)*8-1 -#endif - .long SYMBOL_NAME(gdt) - /* * This gdt setup gives the kernel a 1GB address space at virtual * address 0xC0000000 - space enough for expansion, I hope. + * + * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of + * gdt entries. Ugh. + * + * NOTE! Make sure the gdt descriptor in head.S matches this if you + * change anything. */ ENTRY(gdt) .quad 0x0000000000000000 /* NULL descriptor */ diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 8c16f0204..daa6baf42 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -19,6 +19,11 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); extern void __lock_kernel(void); +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif + /* platform dependent support */ EXPORT_SYMBOL(EISA_bus); EXPORT_SYMBOL(MCA_bus); @@ -39,12 +44,13 @@ EXPORT_SYMBOL(csum_partial_copy); #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(active_kernel_processor); +EXPORT_SYMBOL_NOVERS(kernel_flag); +EXPORT_SYMBOL_NOVERS(active_kernel_processor); EXPORT_SYMBOL(smp_invalidate_needed); EXPORT_SYMBOL_NOVERS(__lock_kernel); /* Global SMP irq stuff */ +EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c new file mode 100644 index 000000000..cc0a19231 --- /dev/null +++ b/arch/i386/kernel/init_task.c @@ -0,0 +1,22 @@ +#include <linux/mm.h> +#include <linux/sched.h> + +#include <asm/pgtable.h> + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance.. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 95a7b525f..e5fb5acb1 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -44,9 +44,6 @@ extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]; #define CR0_NE 32 -static unsigned char cache_21 = 0xff; -static unsigned char cache_A1 = 0xff; - unsigned int local_irq_count[NR_CPUS]; #ifdef __SMP__ atomic_t __intel_bh_counter; @@ -58,51 +55,84 @@ int __intel_bh_counter; static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; #endif -static inline void mask_irq(unsigned int irq_nr) -{ - unsigned char mask; +/* + * This contains the irq mask for both irq controllers + */ +static unsigned int cached_irq_mask = 0xffff; + +#define cached_21 (((char *)(&cached_irq_mask))[0]) +#define cached_A1 (((char *)(&cached_irq_mask))[1]) - mask = 1 << (irq_nr & 7); - if (irq_nr < 8) { - cache_21 |= mask; - outb(cache_21,0x21); +spinlock_t irq_controller_lock; + +/* + * This is always called from an interrupt context + * with local interrupts disabled. Don't worry about + * irq-safe locks. + * + * Note that we always ack the primary irq controller, + * even if the interrupt came from the secondary, as + * the primary will still have routed it. Oh, the joys + * of PC hardware. + */ +static inline void mask_and_ack_irq(int irq_nr) +{ + spin_lock(&irq_controller_lock); + cached_irq_mask |= 1 << irq_nr; + if (irq_nr & 8) { + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); } else { - cache_A1 |= mask; - outb(cache_A1,0xA1); + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); } + outb(0x20,0x20); + spin_unlock(&irq_controller_lock); } -static inline void unmask_irq(unsigned int irq_nr) +static inline void set_irq_mask(int irq_nr) { - unsigned char mask; - - mask = ~(1 << (irq_nr & 7)); - if (irq_nr < 8) { - cache_21 &= mask; - outb(cache_21,0x21); + if (irq_nr & 8) { + outb(cached_A1,0xA1); } else { - cache_A1 &= mask; - outb(cache_A1,0xA1); + outb(cached_21,0x21); } } +/* + * These have to be protected by the spinlock + * before being called. + */ +static inline void mask_irq(unsigned int irq_nr) +{ + cached_irq_mask |= 1 << irq_nr; + set_irq_mask(irq_nr); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + cached_irq_mask &= ~(1 << irq_nr); + set_irq_mask(irq_nr); +} + void disable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&irq_controller_lock, flags); mask_irq(irq_nr); - restore_flags(flags); + spin_unlock_irqrestore(&irq_controller_lock, flags); + synchronize_irq(); } void enable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&irq_controller_lock, flags); unmask_irq(irq_nr); - restore_flags(flags); + spin_unlock_irqrestore(&irq_controller_lock, flags); } /* @@ -133,7 +163,8 @@ void enable_irq(unsigned int irq_nr) #error make irq stub building NR_IRQS dependent and remove me. #endif -BUILD_TIMER_IRQ(FIRST,0,0x01) +BUILD_COMMON_IRQ() +BUILD_IRQ(FIRST,0,0x01) BUILD_IRQ(FIRST,1,0x02) BUILD_IRQ(FIRST,2,0x04) BUILD_IRQ(FIRST,3,0x08) @@ -157,10 +188,6 @@ BUILD_SMP_INTERRUPT(stop_cpu_interrupt) BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt) #endif -/* - * Pointers to the low-level handlers: first the general ones, then the - * fast ones, then the bad ones. - */ static void (*interrupt[17])(void) = { IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt, IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, @@ -168,28 +195,6 @@ static void (*interrupt[17])(void) = { IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt }; -static void (*fast_interrupt[16])(void) = { - fast_IRQ0_interrupt, fast_IRQ1_interrupt, - fast_IRQ2_interrupt, fast_IRQ3_interrupt, - fast_IRQ4_interrupt, fast_IRQ5_interrupt, - fast_IRQ6_interrupt, fast_IRQ7_interrupt, - fast_IRQ8_interrupt, fast_IRQ9_interrupt, - fast_IRQ10_interrupt, fast_IRQ11_interrupt, - fast_IRQ12_interrupt, fast_IRQ13_interrupt, - fast_IRQ14_interrupt, fast_IRQ15_interrupt -}; - -static void (*bad_interrupt[16])(void) = { - bad_IRQ0_interrupt, bad_IRQ1_interrupt, - bad_IRQ2_interrupt, bad_IRQ3_interrupt, - bad_IRQ4_interrupt, bad_IRQ5_interrupt, - bad_IRQ6_interrupt, bad_IRQ7_interrupt, - bad_IRQ8_interrupt, bad_IRQ9_interrupt, - bad_IRQ10_interrupt, bad_IRQ11_interrupt, - bad_IRQ12_interrupt, bad_IRQ13_interrupt, - bad_IRQ14_interrupt, bad_IRQ15_interrupt -}; - /* * Initial irq handlers. */ @@ -240,14 +245,10 @@ int get_irq_list(char *buf) action = irq_action[i]; if (!action) continue; - len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); + len += sprintf(buf+len, "%2d: %10u %s", + i, kstat.interrupts[i], action->name); for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + len += sprintf(buf+len, ", %s", action->name); } len += sprintf(buf+len, "\n"); } @@ -298,13 +299,9 @@ int get_smp_prof_list(char *buf) { for (j=0;j<smp_num_cpus;j++) len+=sprintf(buf+len, "%10d ", int_count[cpu_logical_map[j]][i]); - len += sprintf(buf+len, "%c %s", - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); + len += sprintf(buf+len, " %s", action->name); for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + len += sprintf(buf+len, ", %s", action->name); } len += sprintf(buf+len, "\n"); } @@ -393,16 +390,8 @@ static inline void check_smp_invalidate(int cpu) static unsigned long previous_irqholder; -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } - static inline void wait_on_irq(int cpu, unsigned long where) { - int stuck = INIT_STUCK; int local_count = local_irq_count[cpu]; /* Are we the only one in an interrupt context? */ @@ -421,13 +410,12 @@ static inline void wait_on_irq(int cpu, unsigned long where) * their things before trying to get the lock again. */ for (;;) { - STUCK; check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; if (global_irq_lock) continue; - if (!set_bit(0,&global_irq_lock)) + if (!test_and_set_bit(0,&global_irq_lock)) break; } atomic_add(local_count, &global_irq_count); @@ -456,28 +444,18 @@ void synchronize_irq(void) } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} - static inline void get_irqlock(int cpu, unsigned long where) { - int stuck = INIT_STUCK; - - if (set_bit(0,&global_irq_lock)) { + if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ((unsigned char) cpu == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { do { - STUCK; check_smp_invalidate(cpu); } while (test_bit(0,&global_irq_lock)); - } while (set_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); } /* * Ok, we got the lock bit. @@ -519,7 +497,8 @@ void __global_restore_flags(unsigned long flags) { switch (flags) { case 0: - __global_sti(); + release_irqlock(smp_processor_id()); + __sti(); break; case 1: __global_cli(); @@ -533,56 +512,58 @@ void __global_restore_flags(unsigned long flags) #endif /* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +asmlinkage void do_IRQ(struct pt_regs regs) { + int irq = regs.orig_eax & 0xff; struct irqaction * action; - int do_random, cpu = smp_processor_id(); + int status, cpu; + + /* + * mask and ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + */ + mask_and_ack_irq(irq); + cpu = smp_processor_id(); irq_enter(cpu, irq); kstat.interrupts[irq]++; - /* slow interrupts run with interrupts enabled */ - __sti(); + /* Return with this interrupt masked if no action */ + status = 0; action = *(irq + irq_action); - do_random = 0; - while (action) { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; + if (action) { + do { + status |= action->flags; + action->handler(irq, action->dev_id, ®s); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + + __cli(); + spin_lock(&irq_controller_lock); + unmask_irq(irq); + spin_unlock(&irq_controller_lock); } - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - irq_exit(cpu, irq); -} -/* - * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return - * stuff - the handler is also running with interrupts disabled unless - * it explicitly enables them later. - */ -asmlinkage void do_fast_IRQ(int irq) -{ - struct irqaction * action; - int do_random, cpu = smp_processor_id(); - - irq_enter(cpu, irq); - kstat.interrupts[irq]++; - action = *(irq + irq_action); - do_random = 0; - while (action) { - do_random |= action->flags; - action->handler(irq, action->dev_id, NULL); - action = action->next; - } - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); irq_exit(cpu, irq); + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); + } } int setup_x86_irq(int irq, struct irqaction * new) @@ -597,10 +578,6 @@ int setup_x86_irq(int irq, struct irqaction * new) if (!(old->flags & new->flags & SA_SHIRQ)) return -EBUSY; - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - /* add new interrupt at end of irq queue */ do { p = &old->next; @@ -617,11 +594,9 @@ int setup_x86_irq(int irq, struct irqaction * new) *p = new; if (!shared) { - if (new->flags & SA_INTERRUPT) - set_intr_gate(0x20+irq,fast_interrupt[irq]); - else - set_intr_gate(0x20+irq,interrupt[irq]); + spin_lock(&irq_controller_lock); unmask_irq(irq); + spin_unlock(&irq_controller_lock); } restore_flags(flags); return 0; @@ -676,10 +651,6 @@ void free_irq(unsigned int irq, void *dev_id) save_flags(flags); cli(); *p = action->next; - if (!irq[irq_action]) { - mask_irq(irq); - set_intr_gate(0x20+irq,bad_interrupt[irq]); - } restore_flags(flags); kfree(action); return; @@ -689,7 +660,7 @@ void free_irq(unsigned int irq, void *dev_id) unsigned long probe_irq_on (void) { - unsigned int i, irqs = 0, irqmask; + unsigned int i, irqs = 0; unsigned long delay; /* first, enable any unassigned irqs */ @@ -705,19 +676,17 @@ unsigned long probe_irq_on (void) /* about 100ms delay */; /* now filter out any obviously spurious interrupts */ - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; - return irqs & ~irqmask; + return irqs & ~cached_irq_mask; } int probe_irq_off (unsigned long irqs) { - unsigned int i, irqmask; + unsigned int i; - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; #ifdef DEBUG - printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask); + printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, cached_irq_mask); #endif - irqs &= irqmask; + irqs &= cached_irq_mask; if (!irqs) return 0; i = ffz(~irqs); @@ -729,10 +698,6 @@ int probe_irq_off (unsigned long irqs) __initfunc(void init_IRQ(void)) { int i; - static unsigned char smptrap=0; - if(smptrap) - return; - smptrap=1; /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ @@ -740,7 +705,7 @@ __initfunc(void init_IRQ(void)) outb(LATCH >> 8 , 0x40); /* MSB */ for (i = 0; i < NR_IRQS ; i++) - set_intr_gate(0x20+i,bad_interrupt[i]); + set_intr_gate(0x20+i,interrupt[i]); #ifdef __SMP__ /* diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index 3a349f20a..1f9e89399 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -33,7 +33,6 @@ static inline void irq_enter(int cpu, int irq) static inline void irq_exit(int cpu, int irq) { - __cli(); hardirq_exit(cpu); release_irqlock(cpu); } @@ -63,125 +62,12 @@ static inline void irq_exit(int cpu, int irq) "mov %dx,%ds\n\t" \ "mov %dx,%es\n\t" -/* - * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers, - * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't - * call the routines that do signal handling etc on return, and can have - * more relaxed register-saving etc. They are also atomic, and are thus - * suited for small, fast interrupts like the serial lines or the harddisk - * drivers, which don't actually need signal handling etc. - * - * Also note that we actually save only those registers that are used in - * C subroutines (%eax, %edx and %ecx), so if you do something weird, - * you're on your own. The only segments that are saved (not counting the - * automatic stack and code segment handling) are %ds and %es, and they - * point to kernel space. No messing around with %fs here. - */ -#define SAVE_MOST \ - "cld\n\t" \ - "push %es\n\t" \ - "push %ds\n\t" \ - "pushl %eax\n\t" \ - "pushl %edx\n\t" \ - "pushl %ecx\n\t" \ - "movl $" STR(KERNEL_DS) ",%edx\n\t" \ - "mov %dx,%ds\n\t" \ - "mov %dx,%es\n\t" - -#define RESTORE_MOST \ - "popl %ecx\n\t" \ - "popl %edx\n\t" \ - "popl %eax\n\t" \ - "pop %ds\n\t" \ - "pop %es\n\t" \ - "iret" - -/* - * Some fast irq handlers might want to access saved registers (mostly - * cs or flags) - */ - -struct fast_irq_regs { - long ecx; - long edx; - long eax; - int xds; - int xes; - long eip; - int xcs; - long eflags; - long esp; - int xss; -}; - -/* - * The "inb" instructions are not needed, but seem to change the timings - * a bit - without them it seems that the harddisk driver won't work on - * all hardware. Arghh. - */ -#define ACK_FIRST(mask,nr) \ - "inb $0x21,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \ - "outb %al,$0x21\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tmovb $0x20,%al\n\t" \ - "outb %al,$0x20\n\t" - -#define ACK_SECOND(mask,nr) \ - "inb $0xA1,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \ - "outb %al,$0xA1\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tmovb $0x20,%al\n\t" \ - "outb %al,$0xA0\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\toutb %al,$0x20\n\t" - -#define UNBLK_FIRST(mask) \ - "inb $0x21,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \ - "outb %al,$0x21\n\t" - -#define UNBLK_SECOND(mask) \ - "inb $0xA1,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \ - "outb %al,$0xA1\n\t" - #define IRQ_NAME2(nr) nr##_interrupt(void) #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) -#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) -#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) - -#ifdef __SMP__ - -#define GET_CURRENT \ - "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \ - "movl 32(%ebx), %ebx\n\t" \ - "shrl $22,%ebx\n\t" \ - "andl $0x3C,%ebx\n\t" \ - "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t" - -#else #define GET_CURRENT \ - "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t" - -#endif + "movl %esp, %ebx\n\t" \ + "andl $-8192, %ebx\n\t" #ifdef __SMP__ @@ -205,66 +91,30 @@ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ "pushl $-1\n\t" \ - SAVE_ALL \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ + SAVE_ALL \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ + "addl $4,%esp\n\t" \ "jmp ret_from_intr\n"); #endif /* __SMP__ */ -#define BUILD_IRQ(chip,nr,mask) \ -asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ +#define BUILD_COMMON_IRQ() \ __asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ + "\n" __ALIGN_STR"\n" \ + "common_interrupt:\n\t" \ SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - UNBLK_##chip(mask) \ - "jmp ret_from_intr\n" \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ - "addl $4,%esp\n\t" \ - UNBLK_##chip(mask) \ - RESTORE_MOST \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ - RESTORE_MOST); - -#define BUILD_TIMER_IRQ(chip,nr,mask) \ + "pushl $ret_from_intr\n\t" \ + "jmp "SYMBOL_NAME_STR(do_IRQ)); + +#define BUILD_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ - SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - UNBLK_##chip(mask) \ - "jmp ret_from_intr\n"); + "pushl $"#nr"-256\n\t" \ + "jmp common_interrupt"); /* * x86 profiling function, SMP safe. We might want to do this in @@ -276,15 +126,14 @@ static inline void x86_do_profile (unsigned long eip) extern int _stext; eip -= (unsigned long) &_stext; eip >>= prof_shift; - if (eip < prof_len) - atomic_inc((atomic_t *)&prof_buffer[eip]); - else /* * Dont ignore out-of-bounds EIP values silently, * put them into the last histogram slot, so if * present, they will show up as a sharp peak. */ - atomic_inc((atomic_t *)&prof_buffer[prof_len-1]); + if (eip > prof_len-1) + eip = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[eip]); } } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index fe4723951..33842a21f 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -30,6 +30,7 @@ #include <linux/delay.h> #include <linux/smp.h> #include <linux/reboot.h> +#include <linux/init.h> #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) #include <linux/apm_bios.h> #endif @@ -149,7 +150,8 @@ int cpu_idle(void *unused) current->priority = -100; while(1) { - if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched) + if(cpu_data[smp_processor_id()].hlt_works_ok && + !hlt_counter && !need_resched) __asm("hlt"); /* * tq_scheduler currently assumes we're running in a process @@ -183,7 +185,7 @@ static long no_idt[2] = {0, 0}; static int reboot_mode = 0; static int reboot_thru_bios = 0; -void reboot_setup(char *str, int *ints) +__initfunc(void reboot_setup(char *str, int *ints)) { while(1) { switch (*str) { @@ -324,11 +326,14 @@ void machine_restart(char * __unused) pg0 [0] = 7; - /* Use `swapper_pg_dir' as our page directory. Don't bother with - `SET_PAGE_DIR' because interrupts are disabled and we're rebooting. - This instruction flushes the TLB. */ + /* + * Use `swapper_pg_dir' as our page directory. We bother with + * `SET_PAGE_DIR' because although might be rebooting, but if we change + * the way we set root page dir in the future, then we wont break a + * seldom used feature ;) + */ - __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory"); + SET_PAGE_DIR(current,swapper_pg_dir); /* Write 0x1234 to absolute memory location 0x472. The BIOS reads this on booting to tell it to "Bypass memory test (also warm @@ -473,6 +478,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, int i; struct pt_regs * childregs; + p->tss.tr = _TSS(nr); + p->tss.ldt = _LDT(nr); p->tss.es = KERNEL_DS; p->tss.cs = KERNEL_CS; p->tss.ss = KERNEL_DS; @@ -480,9 +487,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, p->tss.fs = USER_DS; p->tss.gs = USER_DS; p->tss.ss0 = KERNEL_DS; - p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE; - p->tss.tr = _TSS(nr); - childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; + p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p; + childregs = ((struct pt_regs *) (p->tss.esp0)) - 1; p->tss.esp = (unsigned long) childregs; #ifdef __SMP__ p->tss.eip = (unsigned long) ret_from_smpfork; @@ -496,7 +502,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, childregs->eax = 0; childregs->esp = esp; p->tss.back_link = 0; - p->tss.ldt = _LDT(nr); if (p->ldt) { p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); if (p->ldt != NULL) @@ -512,6 +517,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, p->tss.io_bitmap[i] = ~0; if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); + return 0; } diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 920d1bc1c..0dfffd672 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -34,18 +34,6 @@ */ #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs)) -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the TSS. @@ -95,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -105,7 +93,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -115,7 +103,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -146,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -156,7 +144,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -166,12 +154,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -381,7 +369,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index ec5954771..f62744d11 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -247,7 +247,7 @@ static const char * i586model(unsigned int nr) static const char * i686model(unsigned int nr) { static const char *model[] = { - "PPro A-step", "Pentium Pro" + "PPro A-step", "Pentium Pro", "2", "Pentium II" }; if (nr < sizeof(model)/sizeof(char *)) return model[nr]; @@ -279,9 +279,10 @@ static const char * getmodel(int x86, int model) int get_cpuinfo(char * buffer) { int i, len = 0; + int sep_bug; static const char *x86_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", - "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov", + "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov", "16", "17", "18", "19", "20", "21", "22", "mmx", "24", "25", "26", "27", "28", "29", "30", "31" }; @@ -321,10 +322,18 @@ int get_cpuinfo(char * buffer) else len += sprintf(buffer+len, "stepping\t: unknown\n"); + + sep_bug = CD(have_cpuid) && + (CD(x86_capability) & 0x800) && + !memcmp(x86_vendor_id, "GenuineIntel", 12) && + CD(x86) == 6 && + CD(x86_model) < 3 && + CD(x86_mask) < 3; len += sprintf(buffer+len, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" + "sep_bug\t\t: %s\n" "fpu\t\t: %s\n" "fpu_exception\t: %s\n" "cpuid\t\t: %s\n" @@ -332,6 +341,7 @@ int get_cpuinfo(char * buffer) "flags\t\t:", CD(fdiv_bug) ? "yes" : "no", CD(hlt_works_ok) ? "no" : "yes", + sep_bug ? "yes" : "no", CD(hard_math) ? "yes" : "no", (CD(hard_math) && ignore_irq13) ? "yes" : "no", diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 970c8c5d7..3141c5318 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -318,6 +318,14 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) unsigned long signr; struct sigaction * sa; + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if ((regs->xcs & 3) != 3) + return 1; mask = ~current->blocked; while ((signr = current->signal & mask)) { /* @@ -384,10 +392,12 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + lock_kernel(); if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; } + unlock_kernel(); /* fall through */ default: spin_lock_irq(¤t->sigmask_lock); diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index a1590f500..1dc615501 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -1,5 +1,5 @@ /* - * Intel MP v1.1/v1.4 specification support routines for multi-pentium + * Intel MP v1.1/v1.4 specification support routines for multi-pentium * hosts. * * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net> @@ -46,14 +46,15 @@ #include <asm/smp.h> #include <asm/io.h> +#define __KERNEL_SYSCALLS__ +#include <linux/unistd.h> + #include "irq.h" extern unsigned long start_kernel, _etext; extern void update_one_process( struct task_struct *p, - unsigned long ticks, unsigned long user, - unsigned long system); -void setup_APIC_clock (void); - + unsigned long ticks, unsigned long user, + unsigned long system); /* * Some notes on processor bugs: * @@ -67,7 +68,7 @@ void setup_APIC_clock (void); * Pentium * There is a marginal case where REP MOVS on 100MHz SMP * machines with B stepping processors can fail. XXX should provide - * an L1cache=Writethrough or L1cache=off option. + * an L1cache=Writethrough or L1cache=off option. * * B stepping CPU's may hang. There are hardware work arounds * for this. We warn about it in case your board doesnt have the work @@ -91,12 +92,12 @@ void setup_APIC_clock (void); * If this sounds worrying believe me these bugs are ___RARE___ and * there's about nothing of note with C stepping upwards. */ - - + + /* * Why isn't this somewhere standard ?? */ - + extern __inline int max(int a,int b) { if(a>b) @@ -121,7 +122,6 @@ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters static unsigned int num_processors = 1; /* Internal processor count */ static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ -static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */ static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ int apic_version[NR_CPUS]; /* APIC version number */ static volatile int smp_commenced=0; /* Tripped when we start scheduling */ @@ -129,7 +129,6 @@ unsigned long apic_addr = 0xFEE00000; /* Address of APIC (defaults to 0xFEE000 unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */ unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC */ unsigned long apic_retval; /* Just debugging the assembler.. */ -unsigned char *kernel_stacks[NR_CPUS]; /* Kernel stack pointers for CPU's (debugging) */ static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */ @@ -195,10 +194,10 @@ static inline void ack_APIC_irq (void) apic_write(APIC_EOI, 0); } -/* +/* * Checksum an MP configuration block. */ - + static int mpf_checksum(unsigned char *mp, int len) { int sum=0; @@ -210,7 +209,7 @@ static int mpf_checksum(unsigned char *mp, int len) /* * Processor encoding in an MP configuration block */ - + static char *mpc_family(int family,int model) { static char n[32]; @@ -274,11 +273,11 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) /* set the local APIC address */ apic_addr = (unsigned long)phys_to_virt((unsigned long)mpc->mpc_lapic); - + /* * Now process the configuration blocks. */ - + while(count<mpc->mpc_length) { switch(*mpt) @@ -290,13 +289,13 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) if(m->mpc_cpuflag&CPU_ENABLED) { printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, + m->mpc_apicid, mpc_family((m->mpc_cpufeature& CPU_FAMILY_MASK)>>8, (m->mpc_cpufeature& CPU_MODEL_MASK)>>4), m->mpc_apicver); -#ifdef SMP_DEBUG +#ifdef SMP_DEBUG if(m->mpc_featureflag&(1<<0)) printk(" Floating point unit present.\n"); if(m->mpc_featureflag&(1<<7)) @@ -305,7 +304,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) printk(" 64 bit compare & exchange supported.\n"); if(m->mpc_featureflag&(1<<9)) printk(" Internal APIC present.\n"); -#endif +#endif if(m->mpc_cpuflag&CPU_BOOTPROCESSOR) { SMP_PRINTK((" Bootup CPU\n")); @@ -313,10 +312,10 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) } else /* Boot CPU already counted */ num_processors++; - + if(m->mpc_apicid>NR_CPUS) printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); - else + else { cpu_present_map|=(1<<m->mpc_apicid); apic_version[m->mpc_apicid]=m->mpc_apicver; @@ -337,7 +336,7 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) str)); mpt+=sizeof(*m); count+=sizeof(*m); - break; + break; } case MP_IOAPIC: { @@ -346,20 +345,20 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) if(m->mpc_flags&MPC_APIC_USABLE) { apics++; - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid,m->mpc_apicver, - m->mpc_apicaddr); - io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr); - } - mpt+=sizeof(*m); - count+=sizeof(*m); - break; + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid,m->mpc_apicver, + m->mpc_apicaddr); + io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr); + } + mpt+=sizeof(*m); + count+=sizeof(*m); + break; } case MP_INTSRC: { struct mpc_config_intsrc *m= (struct mpc_config_intsrc *)mpt; - + mpt+=sizeof(*m); count+=sizeof(*m); break; @@ -376,29 +375,29 @@ __initfunc(static int smp_read_mpc(struct mp_config_table *mpc)) } if(apics>1) printk("Warning: Multiple APIC's not supported.\n"); - return num_processors; + return num_processors; } /* * Scan the memory blocks for an SMP configuration block. */ - + __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) { unsigned long *bp=phys_to_virt(base); struct intel_mp_floating *mpf; - + SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n", bp,length)); if(sizeof(*mpf)!=16) printk("Error: MPF size\n"); - + while(length>0) { if(*bp==SMP_MAGIC_IDENT) { mpf=(struct intel_mp_floating *)bp; - if(mpf->mpf_length==1 && + if(mpf->mpf_length==1 && !mpf_checksum((unsigned char *)bp,16) && (mpf->mpf_specification == 1 || mpf->mpf_specification == 4) ) @@ -433,7 +432,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) * We know that page 0 is not * used. Steal it for now! */ - + cfg=pg0[0]; pg0[0] = (apic_addr | 7); local_flush_tlb(); @@ -451,7 +450,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) * * END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK * - */ + */ /* * 2 CPUs, numbered 0 & 1. */ @@ -513,6 +512,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */ cpu_logical_map[0] = boot_cpu_id; global_irq_holder = boot_cpu_id; + current->processor = boot_cpu_id; printk("Processors: %d\n", num_processors); /* @@ -534,61 +534,37 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) extern unsigned char trampoline_data []; extern unsigned char trampoline_end []; +static unsigned char *trampoline_base; /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller * has made sure it's suitably aligned. */ - -__initfunc(static void install_trampoline(unsigned char *mp)) + +__initfunc(static unsigned long setup_trampoline(void)) { - memcpy(mp, trampoline_data, trampoline_end - trampoline_data); + memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); + return virt_to_phys(trampoline_base); } /* - * We are called very early to get the low memory for the trampoline/kernel stacks - * This has to be done by mm/init.c to parcel us out nice low memory. We allocate - * the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and - * other things). + * We are called very early to get the low memory for the + * SMP bootup trampoline page. */ - __initfunc(unsigned long smp_alloc_memory(unsigned long mem_base)) { - int size=(num_processors-1)*PAGE_SIZE; /* Number of stacks needed */ - - /* - * Our stacks have to be below the 1Mb line, and mem_base on entry - * is 4K aligned. - */ - - if(virt_to_phys((void *)(mem_base+size))>=0x9F000) - panic("smp_alloc_memory: Insufficient low memory for kernel stacks 0x%lx.\n", mem_base); - kstack_base=(void *)mem_base; - mem_base+=size; - kstack_end=(void *)mem_base; - return mem_base; -} - -/* - * Hand out stacks one at a time. - */ - -__initfunc(static void *get_kernel_stack(void)) -{ - void *stack=kstack_base; - if(kstack_base>=kstack_end) - return NULL; - kstack_base+=PAGE_SIZE; - return stack; + if (virt_to_phys((void *)mem_base) >= 0x9F000) + panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base); + trampoline_base = (void *)mem_base; + return mem_base + PAGE_SIZE; } - /* * The bootstrap kernel entry code has set these up. Save them for * a given CPU */ - + __initfunc(void smp_store_cpu_info(int id)) { struct cpuinfo_x86 *c=&cpu_data[id]; @@ -615,7 +591,7 @@ __initfunc(void smp_store_cpu_info(int id)) * fired off. This allows the BP to have everything in order [we hope]. * At the end of this all the AP's will hit the system scheduling and off * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over + * init into idle(). At this point the scheduler will one day take over * and give them jobs to do. smp_callin is a standard routine * we use to track CPU's as they power up. */ @@ -634,74 +610,276 @@ __initfunc(void smp_callin(void)) extern void calibrate_delay(void); int cpuid=GET_APIC_ID(apic_read(APIC_ID)); unsigned long l; - + /* * Activate our APIC */ - - SMP_PRINTK(("CALLIN %d\n",smp_processor_id())); + + SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id())); l=apic_read(APIC_SPIV); l|=(1<<8); /* Enable */ apic_write(APIC_SPIV,l); /* - * Set up our APIC timer. + * Set up our APIC timer. */ setup_APIC_clock (); sti(); /* * Get our bogomips. - */ + */ calibrate_delay(); SMP_PRINTK(("Stack at about %p\n",&cpuid)); - + /* * Save our processor parameters */ smp_store_cpu_info(cpuid); + /* * Allow the master to continue. - */ + */ set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]); +} + +static int cpucount = 0; + +extern int cpu_idle(void * unused); + +/* + * Activate a secondary processor. + */ +__initfunc(int start_secondary(void *unused)) +{ + smp_callin(); + while (!smp_commenced) + barrier(); + return cpu_idle(NULL); +} + +/* + * Everything has been set up for the secondary + * CPU's - they just need to reload everything + * from the task structure + */ +__initfunc(void initialize_secondary(void)) +{ + struct thread_struct * p = ¤t->tss; + /* - * Until we are ready for SMP scheduling + * We don't actually need to load the full TSS, + * basically just the stack pointer and the eip. */ - load_ldt(0); - local_flush_tlb(); - - while (cpu_number_map[cpuid] == -1) - barrier(); + asm volatile("lldt %%ax": :"a" (p->ldt)); + asm volatile("ltr %%ax": :"a" (p->tr)); + asm volatile( + "movl %0,%%esp\n\t" + "jmp *%1" + : + :"r" (p->esp),"r" (p->eip)); +} - while(!task[cpuid] || current_set[cpuid] != task[cpu_number_map[cpuid]]) - barrier(); +extern struct { + void * esp; + unsigned short ss; +} stack_start; - local_flush_tlb(); - load_TR(cpu_number_map[cpuid]); +__initfunc(static void do_boot_cpu(int i)) +{ + unsigned long cfg; + pgd_t maincfg; + struct task_struct *idle; + unsigned long send_status, accept_status; + int timeout, num_starts, j; + unsigned long start_eip; - while(!smp_commenced) - barrier(); - + /* + * We need an idle process for each processor. + */ + + kernel_thread(start_secondary, NULL, CLONE_PID); + cpucount++; + + idle = task[cpucount]; + if (!idle) + panic("No idle process for CPU %d\n", i); + + idle->processor = i; + cpu_logical_map[cpucount] = i; + cpu_number_map[i] = cpucount; + + /* start_eip had better be page-aligned! */ + start_eip = setup_trampoline(); + + printk("Booting processor %d eip %lx: ", i, start_eip); /* So we see what's up */ + stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); + + /* + * This grunge runs the startup process for + * the targeted processor. + */ + + SMP_PRINTK(("Setting warm reset code and vector.\n")); + + CMOS_WRITE(0xa, 0xf); local_flush_tlb(); + SMP_PRINTK(("1.\n")); + *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; + SMP_PRINTK(("2.\n")); + *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; + SMP_PRINTK(("3.\n")); + + maincfg=swapper_pg_dir[0]; + ((unsigned long *)swapper_pg_dir)[0]=0x102007; + + /* + * Be paranoid about clearing APIC errors. + */ + + if ( apic_version[i] & 0xF0 ) + { + apic_write(APIC_ESR, 0); + accept_status = (apic_read(APIC_ESR) & 0xEF); + } + + /* + * Status is now clean + */ - SMP_PRINTK(("Commenced..\n")); + send_status = 0; + accept_status = 0; + + /* + * Starting actual IPI sequence... + */ + + SMP_PRINTK(("Asserting INIT.\n")); + + /* + * Turn INIT on + */ + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG + | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); /* Send IPI */ + + udelay(200); + SMP_PRINTK(("Deasserting INIT.\n")); + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG + | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); /* Send IPI */ + + /* + * Should we send STARTUP IPIs ? + * + * Determine this based on the APIC version. + * If we don't have an integrated APIC, don't + * send the STARTUP IPIs. + */ + + if ( apic_version[i] & 0xF0 ) + num_starts = 2; + else + num_starts = 0; + + /* + * Run STARTUP IPI loop. + */ + + for (j = 1; !(send_status || accept_status) + && (j <= num_starts) ; j++) + { + SMP_PRINTK(("Sending STARTUP #%d.\n",j)); + apic_write(APIC_ESR, 0); + SMP_PRINTK(("After apic_write.\n")); + + /* + * STARTUP IPI + */ + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD + | APIC_DEST_DM_STARTUP + | (start_eip >> 12)); /* Boot on the stack */ + SMP_PRINTK(("Before start apic_write.\n")); + apic_write(APIC_ICR, cfg); /* Kick the second */ + + SMP_PRINTK(("Startup point 1.\n")); + timeout = 0; + do { + SMP_PRINTK(("Sleeping.\n")); udelay(1000000); + udelay(10); + } while ( (send_status = (apic_read(APIC_ICR) & 0x1000)) + && (timeout++ < 1000)); + udelay(200); + accept_status = (apic_read(APIC_ESR) & 0xEF); + } + SMP_PRINTK(("After Startup.\n")); + + if (send_status) /* APIC never delivered?? */ + printk("APIC never delivered???\n"); + if (accept_status) /* Send accept error */ + printk("APIC delivery error (%lx).\n", accept_status); + + if( !(send_status || accept_status) ) + { + for(timeout=0;timeout<50000;timeout++) + { + if(cpu_callin_map[0]&(1<<i)) + break; /* It has booted */ + udelay(100); /* Wait 5s total for a response */ + } + if(cpu_callin_map[0]&(1<<i)) + { + /* number CPUs logically, starting from 1 (BSP is 0) */ +#if 0 + cpu_number_map[i] = cpucount; + cpu_logical_map[cpucount] = i; +#endif + } + else + { + if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5) + printk("Stuck ??\n"); + else + printk("Not responding.\n"); + } + } + SMP_PRINTK(("CPU has booted.\n")); + + swapper_pg_dir[0]=maincfg; local_flush_tlb(); - sti(); + + /* mark "stuck" area as not stuck */ + *((volatile unsigned long *)phys_to_virt(8192)) = 0; } + /* * Cycle through the processors sending APIC IPI's to boot each. */ - + __initfunc(void smp_boot_cpus(void)) { int i; - int cpucount=0; unsigned long cfg; - pgd_t maincfg; - void *stack; - extern unsigned long init_user_stack[]; - + /* * Initialize the logical to physical cpu number mapping */ @@ -712,12 +890,10 @@ __initfunc(void smp_boot_cpus(void)) /* * Setup boot CPU information */ - - kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */ smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ - cpu_present_map |= (1 << smp_processor_id()); + cpu_present_map |= (1 << hard_smp_processor_id()); cpu_number_map[boot_cpu_id] = 0; active_kernel_processor=boot_cpu_id; @@ -744,11 +920,11 @@ __initfunc(void smp_boot_cpus(void)) */ apic_reg = ioremap(apic_addr,4096); - + if(apic_reg == NULL) panic("Unable to map local apic.\n"); - -#ifdef SMP_DEBUG + +#ifdef SMP_DEBUG { int reg; @@ -785,11 +961,11 @@ __initfunc(void smp_boot_cpus(void)) SMP_PRINTK(("Getting LVT1: %x\n", reg)); } #endif - + /* * Enable the local APIC */ - + cfg=apic_read(APIC_SPIV); cfg|=(1<<8); /* Enable APIC */ apic_write(APIC_SPIV,cfg); @@ -798,15 +974,15 @@ __initfunc(void smp_boot_cpus(void)) /* * Set up our local APIC timer: - */ + */ setup_APIC_clock (); /* * Now scan the cpu present map and fire up the other CPUs. */ - + SMP_PRINTK(("CPU map: %lx\n", cpu_present_map)); - + for(i=0;i<NR_CPUS;i++) { /* @@ -814,213 +990,17 @@ __initfunc(void smp_boot_cpus(void)) */ if (i == boot_cpu_id) continue; - + if ((cpu_present_map & (1 << i)) && (max_cpus < 0 || max_cpus > cpucount+1)) { - unsigned long send_status, accept_status; - int timeout, num_starts, j; - - /* - * We need a kernel stack for each processor. - */ - - stack=get_kernel_stack(); /* We allocated these earlier */ - if(stack==NULL) - panic("No memory for processor stacks.\n"); - - kernel_stacks[i]=(void *)phys_to_virt((unsigned long)stack); - install_trampoline(stack); - - printk("Booting processor %d stack %p: ",i,stack); /* So we set what's up */ - - /* - * This grunge runs the startup process for - * the targeted processor. - */ - - SMP_PRINTK(("Setting warm reset code and vector.\n")); - - /* - * Install a writable page 0 entry. - */ - - cfg=pg0[0]; - - CMOS_WRITE(0xa, 0xf); - pg0[0]=7; - local_flush_tlb(); - SMP_PRINTK(("1.\n")); - *((volatile unsigned short *) phys_to_virt(0x469)) = ((unsigned long)stack)>>4; - SMP_PRINTK(("2.\n")); - *((volatile unsigned short *) phys_to_virt(0x467)) = 0; - SMP_PRINTK(("3.\n")); - - /* - * Protect it again - */ - - pg0[0]= cfg; - local_flush_tlb(); - - /* walken modif - * enable mapping of the first 4M at virtual - * address zero - */ - - maincfg=swapper_pg_dir[0]; - ((unsigned long *)swapper_pg_dir)[0]=0x102007; - - /* no need to local_flush_tlb : - we are setting this up for the slave processor ! */ - - /* - * Be paranoid about clearing APIC errors. - */ - - if ( apic_version[i] & 0xF0 ) - { - apic_write(APIC_ESR, 0); - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - - /* - * Status is now clean - */ - - send_status = 0; - accept_status = 0; - - /* - * Starting actual IPI sequence... - */ - - SMP_PRINTK(("Asserting INIT.\n")); - - /* - * Turn INIT on - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG - | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - udelay(200); - SMP_PRINTK(("Deasserting INIT.\n")); - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG - | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - /* - * Should we send STARTUP IPIs ? - * - * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't - * send the STARTUP IPIs. - */ - - if ( apic_version[i] & 0xF0 ) - num_starts = 2; - else - num_starts = 0; - - /* - * Run STARTUP IPI loop. - */ - - for (j = 1; !(send_status || accept_status) - && (j <= num_starts) ; j++) - { - SMP_PRINTK(("Sending STARTUP #%d.\n",j)); - - apic_write(APIC_ESR, 0); - SMP_PRINTK(("After apic_write.\n")); - - /* - * STARTUP IPI - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD - | APIC_DEST_DM_STARTUP - | (((int)virt_to_phys(stack)) >> 12)); /* Boot on the stack */ - SMP_PRINTK(("Before start apic_write.\n")); - apic_write(APIC_ICR, cfg); /* Kick the second */ - - SMP_PRINTK(("Startup point 1.\n")); - timeout = 0; - do { - SMP_PRINTK(("Sleeping.\n")); udelay(1000000); - udelay(10); - } while ( (send_status = (apic_read(APIC_ICR) & 0x1000)) - && (timeout++ < 1000)); - udelay(200); - - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - SMP_PRINTK(("After Startup.\n")); - - if (send_status) /* APIC never delivered?? */ - printk("APIC never delivered???\n"); - if (accept_status) /* Send accept error */ - printk("APIC delivery error (%lx).\n", accept_status); - - if( !(send_status || accept_status) ) - { - for(timeout=0;timeout<50000;timeout++) - { - if(cpu_callin_map[0]&(1<<i)) - break; /* It has booted */ - udelay(100); /* Wait 5s total for a response */ - } - if(cpu_callin_map[0]&(1<<i)) - { - cpucount++; - /* number CPUs logically, starting from 1 (BSP is 0) */ - cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; - } - else - { - if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5) - printk("Stuck ??\n"); - else - printk("Not responding.\n"); - } - } - SMP_PRINTK(("CPU has booted.\n")); - - /* walken modif - * restore mapping of the first 4M - */ - - swapper_pg_dir[0]=maincfg; - - local_flush_tlb(); - - /* mark "stuck" area as not stuck */ - *((volatile unsigned long *)phys_to_virt(8192)) = 0; + do_boot_cpu(i); } - - /* + + /* * Make sure we unmap all failed CPUs */ - + if (cpu_number_map[i] == -1) cpu_present_map &= ~(1 << i); } @@ -1056,12 +1036,12 @@ __initfunc(void smp_boot_cpus(void)) /* * Allow the user to impress friends. */ - + SMP_PRINTK(("Before bogomips.\n")); if(cpucount==0) { printk("Error: only one processor found.\n"); - cpu_present_map=(1<<smp_processor_id()); + cpu_present_map=(1<<hard_smp_processor_id()); } else { @@ -1071,8 +1051,8 @@ __initfunc(void smp_boot_cpus(void)) if(cpu_present_map&(1<<i)) bogosum+=cpu_data[i].udelay_val; } - printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", - cpucount+1, + printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + cpucount+1, (bogosum+2500)/500000, ((bogosum+2500)/5000)%100); SMP_PRINTK(("Before bogocount - setting activated=1.\n")); @@ -1096,7 +1076,7 @@ __initfunc(void smp_boot_cpus(void)) * IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That * will also boost performance. */ - + void smp_message_pass(int target, int msg, unsigned long data, int wait) { unsigned long flags; @@ -1109,11 +1089,11 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) /* * During boot up send no messages */ - + if(!smp_activated || !smp_commenced) return; - - + + /* * Skip the reschedule if we are waiting to clear a * message at this time. The reschedule cannot wait @@ -1121,7 +1101,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) */ switch (msg) { - case MSG_RESCHEDULE: + case MSG_RESCHEDULE: irq = 0x30; if (smp_cpu_in_msg[p]) return; @@ -1148,21 +1128,21 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) * no data and can occur during a flush.. guess what panic * I got to notice this bug... */ - + /* * We are busy */ - - smp_cpu_in_msg[p]++; + smp_cpu_in_msg[p]++; + /* printk("SMP message pass #%d to %d of %d\n", p, msg, target);*/ - + /* * Wait for the APIC to become ready - this should never occur. Its * a debugging check really. */ - + while(ct<1000) { cfg=apic_read(APIC_ICR); @@ -1171,14 +1151,14 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) ct++; udelay(10); } - + /* * Just pray... there is nothing more we can do */ - + if(ct==1000) printk("CPU #%d: previous IPI still not cleared after 10mS\n", p); - + /* * Program the APIC to deliver the IPI */ @@ -1190,12 +1170,12 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */ cfg=apic_read(APIC_ICR); cfg&=~0xFDFFF; /* Clear bits */ - cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */ + cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */ /* * Set the target requirement */ - + if(target==MSG_ALL_BUT_SELF) { cfg|=APIC_DEST_ALLBUT; @@ -1213,18 +1193,18 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) target_map=(1<<target); cpu_callin_map[0]=0; } - + /* * Send the IPI. The write to APIC_ICR fires this off. */ - + apic_write(APIC_ICR, cfg); __restore_flags(flags); - + /* * Spin waiting for completion */ - + switch(wait) { int stuck; @@ -1247,17 +1227,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) clear_bit(p, &smp_invalidate_needed); --stuck; if (!stuck) { - printk("stuck on smp_invalidate_needed IPI wait\n"); + printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p); break; } } break; } - + /* * Record our completion */ - + smp_cpu_in_msg[p]--; } @@ -1266,14 +1246,17 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) * even with IRQ's off. We have to avoid a pair of crossing flushes * or we are doomed. See the notes about smp_message_pass. */ - + void smp_flush_tlb(void) { unsigned long flags; + +#if 0 if(smp_activated && smp_processor_id()!=active_kernel_processor) { printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor); *(char *)0=0; } +#endif /* printk("SMI-");*/ /* @@ -1282,30 +1265,30 @@ void smp_flush_tlb(void) * may issue a tlb flush. If you break any one of those three change this to an atomic * bus locked or. */ - + smp_invalidate_needed=cpu_present_map; - + /* * Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will * ensure they don't do a spurious flush tlb or miss one. */ - + __save_flags(flags); __cli(); smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2); - + /* * Flush the local TLB */ - - local_flush_tlb(); + local_flush_tlb(); + __restore_flags(flags); - + /* * Completed. */ - + /* printk("SMID\n");*/ } @@ -1315,14 +1298,14 @@ void smp_flush_tlb(void) * * We do profiling in every local tick, statistics/rescheduling * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing a 4 bytes multiplier + * multiplier is 1 and it can be changed by writing the new multiplier * value into /proc/profile. */ unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; -static inline void smp_local_timer_interrupt(struct pt_regs * regs) +void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); @@ -1367,7 +1350,7 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs) kstat.cpu_user += user; kstat.cpu_system += system; - + } else { #ifdef __SMP_PROF__ if (test_bit(cpu,&smp_idle_map)) @@ -1386,14 +1369,11 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs) * We take the 'long' return path, and there every subsystem * grabs the apropriate locks (kernel lock/ irq lock). * - * FIXME: we want to decouple profiling from the 'long path'. + * we might want to decouple profiling from the 'long path', + * and do the profiling totally in assembly. * * Currently this isnt too much of an issue (performancewise), * we can take more than 100K local irqs per second on a 100 MHz P5. - * [ although we notice need_resched too early, thus the way we - * schedule (deliver signals and handle bhs) changes. ] - * - * Possibly we could solve these problems with 'smart irqs'. */ } @@ -1401,6 +1381,9 @@ static inline void smp_local_timer_interrupt(struct pt_regs * regs) * Local APIC timer interrupt. This is the most natural way for doing * local interrupts, but local timer interrupts can be emulated by * broadcast interrupts too. [in case the hw doesnt support APIC timers] + * + * [ if a single-CPU system runs an SMP kernel then we call the local + * interrupt as well. Thus we cannot inline the local irq ... ] */ void smp_apic_timer_interrupt(struct pt_regs * regs) { @@ -1415,7 +1398,7 @@ void smp_apic_timer_interrupt(struct pt_regs * regs) smp_local_timer_interrupt(regs); } -/* +/* * Reschedule call back */ asmlinkage void smp_reschedule_interrupt(void) @@ -1437,11 +1420,11 @@ asmlinkage void smp_reschedule_interrupt(void) */ asmlinkage void smp_invalidate_interrupt(void) { - if (clear_bit(smp_processor_id(), &smp_invalidate_needed)) + if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed)) local_flush_tlb(); ack_APIC_irq (); -} +} /* * CPU halt call-back @@ -1471,11 +1454,11 @@ asmlinkage void smp_stop_cpu_interrupt(void) * but we do not accept timer interrupts yet. We only allow the BP * to calibrate. */ -static unsigned int get_8254_timer_count (void) +__initfunc(static unsigned int get_8254_timer_count (void)) { unsigned int count; - outb_p(0x00, 0x43); + outb_p(0x00, 0x43); count = inb_p(0x40); count |= inb_p(0x40) << 8; @@ -1500,7 +1483,7 @@ static unsigned int get_8254_timer_count (void) void setup_APIC_timer (unsigned int clocks) { - unsigned long lvtt1_value; + unsigned long lvtt1_value; unsigned int tmp_value; /* @@ -1508,8 +1491,8 @@ void setup_APIC_timer (unsigned int clocks) * mode. With the IO APIC we can re-route the external timer * interrupt and broadcast it as an NMI to all CPUs, so no pain. * - * NOTE: this trap vector (0x41) and the gate in BUILD_SMP_TIMER_INTERRUPT - * should be the same ;) + * NOTE: this trap vector (0x41) and the gate in + * BUILD_SMP_TIMER_INTERRUPT should be the same ;) */ tmp_value = apic_read(APIC_LVTT); lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41; @@ -1526,7 +1509,7 @@ void setup_APIC_timer (unsigned int clocks) apic_write(APIC_TMICT, clocks/APIC_DIVISOR); } -void wait_8254_wraparound (void) +__initfunc(void wait_8254_wraparound (void)) { unsigned int curr_count, prev_count=~0; int delta; @@ -1560,11 +1543,12 @@ void wait_8254_wraparound (void) * APIC irq that way. */ -int calibrate_APIC_clock (void) +__initfunc(int calibrate_APIC_clock (void)) { unsigned long long t1,t2; long tt1,tt2; long calibration_result; + int i; printk("calibrating APIC timer ... "); @@ -1589,10 +1573,12 @@ int calibrate_APIC_clock (void) RTDSC(t1); tt1=apic_read(APIC_TMCCT); +#define LOOPS (HZ/10) /* - * lets wait until we get to the next wrapround: + * lets wait LOOPS wraprounds: */ - wait_8254_wraparound (); + for (i=0; i<LOOPS; i++) + wait_8254_wraparound (); tt2=apic_read(APIC_TMCCT); RTDSC(t2); @@ -1605,46 +1591,47 @@ int calibrate_APIC_clock (void) * underflown to be exact, as the timer counts down ;) */ - calibration_result = (tt1-tt2)*APIC_DIVISOR; + calibration_result = (tt1-tt2)*APIC_DIVISOR/LOOPS; - printk("\n..... %ld CPU clocks in 1 timer chip tick.\n", - (unsigned long)(t2-t1)); + SMP_PRINTK(("\n..... %ld CPU clocks in 1 timer chip tick.", + (unsigned long)(t2-t1)/LOOPS)); - printk("..... %ld APIC bus clocks in 1 timer chip tick.\n", - calibration_result); + SMP_PRINTK(("\n..... %ld APIC bus clocks in 1 timer chip tick.", + calibration_result)); - printk("..... CPU clock speed is %ld.%ld MHz.\n", - ((long)(t2-t1))/(1000000/HZ), - ((long)(t2-t1))%(1000000/HZ) ); + printk("\n..... CPU clock speed is %ld.%04ld MHz.\n", + ((long)(t2-t1)/LOOPS)/(1000000/HZ), + ((long)(t2-t1)/LOOPS)%(1000000/HZ) ); - printk("..... APIC bus clock speed is %ld.%ld MHz.\n", + printk("..... APIC bus clock speed is %ld.%04ld MHz.\n", calibration_result/(1000000/HZ), calibration_result%(1000000/HZ) ); +#undef LOOPS return calibration_result; } static unsigned int calibration_result; -void setup_APIC_clock (void) +__initfunc(void setup_APIC_clock (void)) { int cpu = smp_processor_id(); - unsigned long flags; + unsigned long flags; static volatile int calibration_lock; save_flags(flags); cli(); - printk("setup_APIC_clock() called.\n"); + SMP_PRINTK(("setup_APIC_clock() called.\n")); /* * [ setup_APIC_clock() is called from all CPUs, but we want * to do this part of the setup only once ... and it fits * here best ] */ - if (!set_bit(0,&calibration_lock)) { + if (!test_and_set_bit(0,&calibration_lock)) { calibration_result=calibrate_APIC_clock(); /* @@ -1656,9 +1643,9 @@ void setup_APIC_clock (void) /* * Other CPU is calibrating, wait for finish: */ - printk("waiting for other CPU calibrating APIC timer ... "); + SMP_PRINTK(("waiting for other CPU calibrating APIC ... ")); while (calibration_lock == 1); - printk("done, continuing.\n"); + SMP_PRINTK(("done, continuing.\n")); } /* @@ -1669,16 +1656,8 @@ void setup_APIC_clock (void) prof_counter[cpu] = prof_multiplier[cpu] = 1; /* - * FIXME: i sporadically see booting problems (keyboard irq is - * lost, looks like the timer irq isnt working or some irq - * lock is messed up). Once we reboot the bug doesnt showu - * up anymore. - * - * i'm quite certain it's a timing problem/race condition in - * the bootup logic, not a hw bug. It might have been gone - * meanwhile, tell me if you see it. + * We ACK the APIC, just in case there is something pending. */ - ack_APIC_irq (); restore_flags(flags); @@ -1686,7 +1665,7 @@ void setup_APIC_clock (void) /* * the frequency of the profiling timer can be changed - * by writing 4 bytes into /proc/profile. + * by writing a multiplier value into /proc/profile. * * usually you want to run this on all CPUs ;) */ @@ -1697,8 +1676,8 @@ int setup_profiling_timer (unsigned int multiplier) /* * Sanity check. [at least 500 APIC cycles should be - * between APIC interrupts as a rule of thumb, rather be - * careful as irq flooding renders the system unusable] + * between APIC interrupts as a rule of thumb, to avoid + * irqs flooding us] */ if ( (!multiplier) || (calibration_result/multiplier < 500)) return -EINVAL; diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 6a7d6b461..e45cc7279 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -23,6 +23,7 @@ #include <linux/time.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/smp.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -379,11 +380,15 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) do_timer(regs); /* * In the SMP case we use the local APIC timer interrupt to do the - * profiling. + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. */ #ifndef __SMP__ if (!user_mode(regs)) x86_do_profile(regs->eip); +#else + if (!smp_found_config) + smp_local_timer_interrupt(regs); #endif /* diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S index 63bc51c5e..d0a726f6b 100644 --- a/arch/i386/kernel/trampoline.S +++ b/arch/i386/kernel/trampoline.S @@ -21,13 +21,9 @@ * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. * - * On the transition to protected mode, this page appears at - * address 8192, so protected mode addresses are with regard - * to p_base. - * * If you work on this file, check the object module with objdump * --full-contents --reloc to make sure there are no relocation - * entries. + * entries except for the gdt one.. */ #include <linux/linkage.h> @@ -39,15 +35,10 @@ ENTRY(trampoline_data) r_base = . -p_base = . - 8192 mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov %ax, %cx # Pass stack info to the 32bit boot - shl $4, %cx # Segment -> Offset - add $4096, %cx # End of page is wanted - mov $1, %bx # Flag an SMP trampoline cli # We should be safe anyway @@ -71,37 +62,7 @@ idt_48: gdt_48: .word 0x0800 # gdt limit = 2048, 256 GDT entries - .word gdt - p_base, 0x0 # gdt base = gdt (first SMP CPU) - # we load the others with first table - # saves rewriting gdt_48 for each -gdt: - .word 0, 0, 0, 0 # dummy - - .word 0, 0, 0, 0 # unused - -# walken modif - - .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 # base address = 0 - .word 0x9A00 # code read / exec - .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) - - .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 # base address = 0 - .word 0x9200 # data read / write - .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) - -# walken modif - -# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) -# .word 0x0000 # base address = 0 -# .word 0x9A00 # code read / exec -# .word 0x00C0 # granularity = 4096, 386 - -# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) -# .word 0x0000 # base address = 0 -# .word 0x9200 # data read / write -# .word 0x00C0 # granularity = 4096, 386 + .long gdt-0xc0000000 # gdt base = gdt (first SMP CPU) .globl SYMBOL_NAME(trampoline_end) SYMBOL_NAME_LABEL(trampoline_end) diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 905cf5b13..696e37004 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -23,10 +23,12 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> +#include <asm/spinlock.h> asmlinkage int system_call(void); asmlinkage void lcall7(void); @@ -121,7 +123,7 @@ static void show_registers(struct pt_regs *regs) unsigned long esp; unsigned short ss; unsigned long *stack, addr, module_start, module_end; - extern char start_kernel, _etext; + extern char _stext, _etext; esp = (unsigned long) ®s->esp; ss = KERNEL_DS; @@ -129,8 +131,8 @@ static void show_registers(struct pt_regs *regs) esp = regs->esp; ss = regs->xss & 0xffff; } - printk("CPU: %d\n", smp_processor_id()); - printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", @@ -138,10 +140,8 @@ static void show_registers(struct pt_regs *regs) printk("ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); store_TR(i); - if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) - printk("Corrupted stack page\n"); printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, 0xffff & i, current->kernel_stack_page); + current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); stack = (unsigned long *) esp; for(i=0; i < kstack_depth_to_print; i++) { if (((long) stack & 4095) == 0) @@ -166,7 +166,7 @@ static void show_registers(struct pt_regs *regs) * down the cause of the crash will be able to figure * out the call path that was taken. */ - if (((addr >= (unsigned long) &start_kernel) && + if (((addr >= (unsigned long) &_stext) && (addr <= (unsigned long) &_etext)) || ((addr >= module_start) && (addr <= module_end))) { if (i && ((i % 8) == 0)) @@ -181,13 +181,19 @@ static void show_registers(struct pt_regs *regs) printk("\n"); } +spinlock_t die_lock; + /*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err) { if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3) return; console_verbose(); + spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); +do { int i=2000000000; while (i) i--; } while (0); +do { int i=2000000000; while (i) i--; } while (0); + spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -235,18 +241,45 @@ out: unlock_kernel(); } -asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +static void mem_parity_error(unsigned char reason, struct pt_regs * regs) { - printk("NMI\n"); show_registers(regs); -#ifdef CONFIG_SMP_NMI_INVAL - smp_flush_tlb_rcv(); -#else -#ifndef CONFIG_IGNORE_NMI printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); - printk("You probably have a hardware problem with your RAM chips or a\n"); - printk("power saving mode enabled.\n"); -#endif -#endif + printk("You probably have a hardware problem with your RAM chips\n"); +} + +static void io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk("NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason |= 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); +} + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + unsigned char reason = inb(0x61); + + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + if (!(reason & 0xc0)) + unknown_nmi_error(reason, regs); } asmlinkage void do_debug(struct pt_regs * regs, long error_code) @@ -380,15 +413,7 @@ __initfunc(void trap_init(void)) { int i; struct desc_struct * p; - static int smptrap=0; - - if(smptrap) - { - __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); - load_ldt(0); - return; - } - smptrap++; + if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) EISA_bus = 1; set_call_gate(&default_ldt,lcall7); diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index bfba24327..a09fa6419 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -81,8 +81,8 @@ asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) printk("vm86: could not access userspace vm86_info\n"); do_exit(SIGSEGV); } - current->tss.esp0 = current->saved_kernel_stack; - current->saved_kernel_stack = 0; + current->tss.esp0 = current->tss.saved_esp0; + current->tss.saved_esp0 = 0; ret = KVM86->regs32; unlock_kernel(); return ret; @@ -137,7 +137,7 @@ asmlinkage int sys_vm86old(struct vm86_struct * v86) lock_kernel(); tsk = current; - if (tsk->saved_kernel_stack) + if (tsk->tss.saved_esp0) goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, @@ -187,7 +187,7 @@ asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86) /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */ ret = -EPERM; - if (tsk->saved_kernel_stack) + if (tsk->tss.saved_esp0) goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, @@ -247,7 +247,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk * Save old state, set default return value (%eax) to 0 */ info->regs32->eax = 0; - tsk->saved_kernel_stack = tsk->tss.esp0; + tsk->tss.saved_esp0 = tsk->tss.esp0; tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0; tsk->tss.screen_bitmap = info->screen_bitmap; @@ -601,11 +601,17 @@ static inline void free_vm86_irq(int irqnumber) static inline int task_valid(struct task_struct *tsk) { struct task_struct *p; + int ret = 0; + read_lock(&tasklist_lock); for_each_task(p) { - if ((p == tsk) && (p->sig)) return 1; + if ((p == tsk) && (p->sig)) { + ret = 1; + break; + } } - return 0; + read_unlock(&tasklist_lock); + return ret; } static inline void handle_irq_zombies(void) diff --git a/arch/i386/lib/locks.S b/arch/i386/lib/locks.S index b9d8b0a9c..30a5bc432 100644 --- a/arch/i386/lib/locks.S +++ b/arch/i386/lib/locks.S @@ -10,22 +10,25 @@ * %eax contains callers PC and %edx holds this cpu ID. */ ENTRY(__lock_kernel) - pushl %eax ! return address 1: lock btsl $0, SYMBOL_NAME(kernel_flag) jnc 3f + sti 2: btl %dl, SYMBOL_NAME(smp_invalidate_needed) jnc 0f lock btrl %dl, SYMBOL_NAME(smp_invalidate_needed) jnc 0f + pushl %eax movl %cr3, %eax movl %eax, %cr3 + popl %eax 0: btl $0, SYMBOL_NAME(kernel_flag) jc 2b + cli jmp 1b 3: diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S index ff2443c40..faddbf4ec 100644 --- a/arch/i386/lib/semaphore.S +++ b/arch/i386/lib/semaphore.S @@ -13,16 +13,17 @@ * there is contention on the semaphore. */ ENTRY(__down_failed) - pushl %eax /* return address */ + pushl %eax /* save %eax */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__down) popl %ecx /* restore %ecx (count on __down not changing it) */ popl %edx /* restore %edx */ + popl %eax /* restore %eax */ ret +/* Don't save/restore %eax, because that will be our return value */ ENTRY(__down_failed_interruptible) - pushl %eax /* return address */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__down_interruptible) @@ -31,10 +32,11 @@ ENTRY(__down_failed_interruptible) ret ENTRY(__up_wakeup) - pushl %eax /* return address */ + pushl %eax /* save %eax */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__up) popl %ecx /* restore %ecx (count on __up not changing it) */ popl %edx /* restore %edx */ + popl %eax /* restore %eax */ ret diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 65a4a67d3..b0404a6a9 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -49,7 +49,7 @@ good_area: start &= PAGE_MASK; for (;;) { - do_wp_page(current, vma, start, 1); + handle_mm_fault(current,vma, start, 1); if (!size) break; size--; @@ -86,10 +86,6 @@ bad_area: */ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) { - void (*handler)(struct task_struct *, - struct vm_area_struct *, - unsigned long, - int); struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; struct vm_area_struct * vma; @@ -128,10 +124,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) */ good_area: write = 0; - handler = do_no_page; switch (error_code & 3) { default: /* 3: write, present */ - handler = do_wp_page; #ifdef TEST_VERIFY_AREA if (regs->cs == KERNEL_CS) printk("WP fault at %08lx\n", regs->eip); @@ -148,7 +142,7 @@ good_area: if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handler(tsk, vma, address, write); + handle_mm_fault(tsk, vma, address, write); up(&mm->mmap_sem); /* * Did it hit the DOS screen memory VA from vm86 mode? @@ -169,7 +163,10 @@ bad_area: /* Are we prepared to handle this fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { - printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup); + printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", + current->comm, + regs->eip, + fixup); regs->eip = fixup; goto out; } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 173649338..c8371aa81 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -139,12 +139,23 @@ extern char __init_begin, __init_end; #define write_cr4 ".byte 0x0f,0x22,0xe0" #endif -#define set_in_cr4(x) \ -__asm__(read_cr4 "\n\t" \ - "orl %0,%%eax\n\t" \ - write_cr4 \ - : : "i" (x) \ - :"ax"); +/* + * Save the cr4 feature set we're using (ie + * Pentium 4MB enable and PPro Global page + * enable), so that any CPU's that boot up + * after us can get the correct flags. + */ +unsigned long mmu_cr4_features __initdata = 0; + +static inline void set_in_cr4(unsigned long mask) +{ + mmu_cr4_features |= mask; + __asm__(read_cr4 "\n\t" + "orl %0,%%eax\n\t" + write_cr4 + : : "irg" (mask) + :"ax"); +} /* * paging_init() sets up the page tables - note that the first 4MB are diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds index 6d1195013..7a1fd3d08 100644 --- a/arch/i386/vmlinux.lds +++ b/arch/i386/vmlinux.lds @@ -13,6 +13,7 @@ SECTIONS *(.fixup) *(.gnu.warning) } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 939a80387..7548a8dc8 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -24,19 +24,9 @@ ifneq ($(COMPILE_ARCH),$(ARCH)) CROSS_COMPILE = m68k-linux- endif -# -# Set these to indicate how to link it.. -# -# -zmagic: -# -# LINKFLAGS = -Ttext 0x100000 -# -# -qmagic (we need to remove the 32 byte header for bootup purposes) -# - -LINKFLAGS = -Ttext 0x1000 +LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds -CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce +CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 ifdef CONFIG_OPTIMIZE_040 CFLAGS := $(CFLAGS) -m68040 diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c index c97609611..eb72970d7 100644 --- a/arch/m68k/amiga/amifb.c +++ b/arch/m68k/amiga/amifb.c @@ -50,12 +50,14 @@ #include <linux/delay.h> #include <linux/config.h> #include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> + #include <asm/uaccess.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/amigahw.h> #include <asm/amigaints.h> -#include <linux/fb.h> #define DEBUG @@ -1802,7 +1804,7 @@ static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con) * Initialisation */ -struct fb_info *amiga_fb_init(long *mem_start) +__initfunc(struct fb_info *amiga_fb_init(long *mem_start)) { int err, tag, i; u_long chipptr; diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index b527a8c6c..9df5083c1 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/kernel_stat.h> +#include <linux/init.h> #include <asm/system.h> #include <asm/irq.h> @@ -68,7 +69,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) * the amiga IRQ handling routines. */ -void amiga_init_IRQ(void) +__initfunc(void amiga_init_IRQ(void)) { int i; diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c index f2e826023..1058270dd 100644 --- a/arch/m68k/amiga/amikeyb.c +++ b/arch/m68k/amiga/amikeyb.c @@ -22,6 +22,7 @@ #include <linux/kd.h> #include <linux/random.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/amigaints.h> #include <asm/amigahw.h> @@ -295,7 +296,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) } } -int amiga_keyb_init(void) +__initfunc(int amiga_keyb_init(void)) { if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) return -EIO; diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index b2b2e3055..d5656d170 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/timer.h> +#include <linux/init.h> #include <asm/system.h> #include <asm/amigahw.h> @@ -39,7 +40,7 @@ u_short amiga_audio_period = MAX_PERIOD; static u_long clock_constant; -static void init_sound(void) +__initfunc(static void init_sound(void)) { snd_data = amiga_chip_alloc(sizeof(sine_data)); if (!snd_data) { @@ -84,7 +85,7 @@ void amiga_mksound( unsigned int hz, unsigned int ticks ) custom.aud[2].audlc = snd_data; custom.aud[2].audlen = sizeof(sine_data)/2; custom.aud[2].audper = (u_short)period; - custom.aud[2].audvol = 64; /* maxvol */ + custom.aud[2].audvol = 32; /* 50% of maxvol */ if (ticks) { sound_timer.expires = jiffies + ticks; diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c index 237662c93..50d5a0de0 100644 --- a/arch/m68k/amiga/chipram.c +++ b/arch/m68k/amiga/chipram.c @@ -8,6 +8,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/amigahw.h> struct chip_desc { @@ -21,19 +22,18 @@ struct chip_desc { #define DP(ptr) ((struct chip_desc *)(ptr)) u_long amiga_chip_size; -static unsigned long chipavail; /*MILAN*/ +static unsigned long chipavail; -/*MILAN*/ unsigned long amiga_chip_avail( void ) { #ifdef DEBUG - printk("chip_avail : %ld bytes\n",chipavail); + printk("chip_avail : %ld bytes\n",chipavail); #endif - return chipavail; + return chipavail; } -void amiga_chip_init (void) +__initfunc(void amiga_chip_init (void)) { struct chip_desc *dp; diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index 02b1ad564..408dcbf5a 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -15,6 +15,7 @@ #include <linux/sched.h> #include <linux/errno.h> #include <linux/kernel_stat.h> +#include <linux/init.h> #include <asm/irq.h> #include <asm/amigahw.h> @@ -152,7 +153,7 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp) amiga_do_irq_list(base->server_irq, fp, &base->server); } -void cia_init_IRQ(struct ciabase *base) +__initfunc(void cia_init_IRQ(struct ciabase *base)) { int i; diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 8e6ae531c..08396a5bc 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -20,6 +20,7 @@ #include <linux/kd.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/init.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -148,7 +149,7 @@ int amiga_parse_bootinfo(const struct bi_record *record) * Setup the Amiga configuration info */ -void config_amiga(void) +__initfunc(void config_amiga(void)) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -376,8 +377,8 @@ void config_amiga(void) static unsigned short jiffy_ticks; -static void amiga_sched_init(void (*timer_routine)(int, void *, - struct pt_regs *)) +__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *))) { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -796,7 +797,7 @@ void amiga_serial_gets(char *s, int len) } #endif -static void amiga_debug_init(void) +__initfunc(static void amiga_debug_init(void)) { if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ diff --git a/arch/m68k/amiga/cyberfb.c b/arch/m68k/amiga/cyberfb.c index d74d52c4f..31e2a4608 100644 --- a/arch/m68k/amiga/cyberfb.c +++ b/arch/m68k/amiga/cyberfb.c @@ -29,12 +29,13 @@ #include <linux/tty.h> #include <linux/malloc.h> #include <linux/delay.h> +#include <linux/zorro.h> +#include <linux/fb.h> +#include <linux/init.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/irq.h> -#include <linux/zorro.h> #include <asm/pgtable.h> -#include <linux/fb.h> #include "s3blit.h" @@ -1157,7 +1158,7 @@ void Cyber_video_setup(char *options, int *ints) * Initialization */ -struct fb_info *Cyber_fb_init(long *mem_start) +__initfunc(struct fb_info *Cyber_fb_init(long *mem_start)) { int err; struct Cyber_fb_par par; diff --git a/arch/m68k/amiga/retz3fb.c b/arch/m68k/amiga/retz3fb.c index 4885e48f7..49a0853bc 100644 --- a/arch/m68k/amiga/retz3fb.c +++ b/arch/m68k/amiga/retz3fb.c @@ -30,1762 +30,12 @@ #include <linux/malloc.h> #include <linux/delay.h> #include <linux/fb.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/irq.h> #include <linux/zorro.h> -#include <asm/pgtable.h> - -#include "retz3fb.h" - -/* #define DEBUG if(1) */ -#define DEBUG if(0) - -/* - * Reserve space for one pattern line. - * - * For the time being we only support 4MB boards! - */ - -#define PAT_MEM_SIZE 16*3 -#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) - -#define arraysize(x) (sizeof(x)/sizeof(*(x))) - -struct retz3_fb_par { - int xres; - int yres; - int xres_vir; - int yres_vir; - int xoffset; - int yoffset; - int bpp; - - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - - int pixclock; - int left_margin; /* time from sync to picture */ - int right_margin; /* time from picture to sync */ - int upper_margin; /* time from sync to picture */ - int lower_margin; - int hsync_len; /* length of horizontal sync */ - int vsync_len; /* length of vertical sync */ - int vmode; -}; - -struct display_data { - long h_total; /* Horizontal Total */ - long h_sstart; /* Horizontal Sync Start */ - long h_sstop; /* Horizontal Sync Stop */ - long h_bstart; /* Horizontal Blank Start */ - long h_bstop; /* Horizontal Blank Stop */ - long h_dispend; /* Horizontal Display End */ - long v_total; /* Vertical Total */ - long v_sstart; /* Vertical Sync Start */ - long v_sstop; /* Vertical Sync Stop */ - long v_bstart; /* Vertical Blank Start */ - long v_bstop; /* Vertical Blank Stop */ - long v_dispend; /* Horizontal Display End */ -}; - -static struct retz3_fb_par current_par; - -static int current_par_valid = 0; -static int currcon = 0; - -static struct display disp[MAX_NR_CONSOLES]; -static struct fb_info fb_info; - -static int node; /* node of the /dev/fb?current file */ - - -/* - * Switch for Chipset Independency - */ - -static struct fb_hwswitch { - - /* Initialisation */ - - int (*init)(void); - - /* Display Control */ - - int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par); - int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); - int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); - int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned - int *green, unsigned int *blue, unsigned int *transp); - int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int - green, unsigned int blue, unsigned int transp); - void (*blank)(int blank); -} *fbhw; - - -/* - * Frame Buffer Name - */ - -static char retz3_fb_name[16] = "RetinaZ3"; - - -static int z3_key = 0; -static unsigned char retz3_color_table [256][4]; -static unsigned long z3_mem; -static unsigned long z3_fbmem; -static unsigned long z3_size; -static volatile unsigned char *z3_regs; - -static long *memstart; - - -/* - * Predefined Video Mode Names - */ - -static char *retz3_fb_modenames[] = { - - /* - * Autodetect (Default) Video Mode - */ - - "default", - - /* - * Predefined Video Modes - */ - - "640x480", /* RetinaZ3 8 bpp */ - "800x600", /* RetinaZ3 8 bpp */ - "1024x768i", - "640x480-16", /* RetinaZ3 16 bpp */ - "640x480-24", /* RetinaZ3 24 bpp */ - - /* - * Dummy Video Modes - */ - - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - - /* - * User Defined Video Modes - * - * This doesn't work yet!! - */ - - "user0", "user1", "user2", "user3", - "user4", "user5", "user6", "user7" -}; - -/* - * A small info on how to convert XFree86 timing values into fb - * timings - by Frank Neumann: - * -An XFree86 mode line consists of the following fields: - "800x600" 50 800 856 976 1040 600 637 643 666 - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - -The fields in the fb_var_screeninfo structure are: - unsigned long pixclock; * pixel clock in ps (pico seconds) * - unsigned long left_margin; * time from sync to picture * - unsigned long right_margin; * time from picture to sync * - unsigned long upper_margin; * time from sync to picture * - unsigned long lower_margin; - unsigned long hsync_len; * length of horizontal sync * - unsigned long vsync_len; * length of vertical sync * - -1) Pixelclock: - xfree: in MHz - fb: In Picoseconds (ps) - - pixclock = 1000000 / DCF - -2) horizontal timings: - left_margin = HFL - SH2 - right_margin = SH1 - HR - hsync_len = SH2 - SH1 - -3) vertical timings: - upper_margin = VFL - SV2 - lower_margin = SV1 - VR - vsync_len = SV2 - SV1 - -Good examples for VESA timings can be found in the XFree86 source tree, -under "programs/Xserver/hw/xfree86/doc/modeDB.txt". -*/ - -/* - * Predefined Video Mode Definitions - */ - -static struct fb_var_screeninfo retz3_fb_predefined[] = { - - /* - * Autodetect (Default) Video Mode - */ - - { 0, }, - - /* - * Predefined Video Modes - */ - - /* - * NB: it is very important to adjust the pixel-clock to the color-depth. - */ - - { - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - /* - ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - */ - { - /* 800 x 600, 8 bpp */ - 800, 600, 800, 600, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - /* - ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - */ - { - /* 1024 x 768, 8 bpp, interlaced */ - 1024, 768, 1024, 768, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED - }, - { - 640, 480, 640, 480, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - { - 640, 480, 640, 480, 0, 0, 24, 0, - {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - - /* - * Dummy Video Modes - */ - - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, - { 0, }, { 0, }, - - /* - * User Defined Video Modes - */ - - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } -}; - - -#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined) -#define NUM_PREDEF_MODES (5) - - -static int z3fb_inverse = 0; -static int z3fb_mode = 0; - - -/* - * Interface used by the world - */ - -int retz3_probe(void); -void retz3_video_setup(char *options, int *ints); - -static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con); -static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con); -static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con); -static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); -static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); -static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con); -static int retz3_fb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con); - - -/* - * Interface to the low level console driver - */ - -struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */ -static int z3fb_switch(int con); -static int z3fb_updatevar(int con); -static void z3fb_blank(int blank); -static int z3fb_setcmap(struct fb_cmap *cmap, int con); - - -/* - * Accelerated Functions used by the low level console driver - */ - -void retz3_bitblt(struct fb_var_screeninfo *scr, - unsigned short curx, unsigned short cury, unsigned - short destx, unsigned short desty, unsigned short - width, unsigned short height, unsigned short cmd, - unsigned short mask); -void retz3_fill(unsigned short x, unsigned short y, unsigned short - width, unsigned short height, unsigned short mode, - unsigned short color); - -/* - * Hardware Specific Routines - */ - -static int retz3_init(void); -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, - struct retz3_fb_par *par); -static int retz3_decode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par); -static int retz3_encode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par); -static int retz3_getcolreg(unsigned int regno, unsigned int *red, - unsigned int *green, unsigned int *blue, - unsigned int *transp); -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp); -static void retz3_blank(int blank); - - -/* - * Internal routines - */ - -static void retz3_fb_get_par(struct retz3_fb_par *par); -static void retz3_fb_set_par(struct retz3_fb_par *par); -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); -static struct fb_cmap *get_default_colormap(int bpp); -static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc); -static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc); -static void do_install_cmap(int con); -static void memcpy_fs(int fsfromto, void *to, void *from, int len); -static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto); -static int alloc_cmap(struct fb_cmap *cmap, int len, int transp); -static void retz3_fb_set_disp(int con); -static int get_video_mode(const char *name); - - -/* -------------------- Hardware specific routines -------------------------- */ - -static unsigned short find_fq(unsigned int freq) -{ - unsigned long f; - long tmp; - long prev = 0x7fffffff; - long n2, n1 = 3; - unsigned long m; - unsigned short res = 0; - - if (freq <= 31250000) - n2 = 3; - else if (freq <= 62500000) - n2 = 2; - else if (freq <= 125000000) - n2 = 1; - else if (freq <= 250000000) - n2 = 0; - else - return(0); - - - do { - f = freq >> (10 - n2); - - m = (f * n1) / (14318180/1024); - - if (m > 129) - break; - - tmp = (((m * 14318180) >> n2) / n1) - freq; - if (tmp < 0) - tmp = -tmp; - - if (tmp < prev) { - prev = tmp; - res = (((n2 << 5) | (n1-2)) << 8) | (m-2); - } - - } while ( (++n1) <= 21); - - return res; -} - - -static int retz3_set_video(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - float freq_f; - long freq; - - int xres, hfront, hsync, hback; - int yres, vfront, vsync, vback; - unsigned char tmp; - unsigned short best_freq; - struct display_data data; - - short clocksel = 0; /* Apparantly this is always zero */ - - int bpp = var->bits_per_pixel; - - /* - * XXX - */ - if (bpp == 24) - return 0; - - if ((bpp != 8) && (bpp != 16) && (bpp != 24)) - return -EFAULT; - - par->xoffset = 0; - par->yoffset = 0; - - xres = var->xres * bpp / 4; - hfront = var->right_margin * bpp / 4; - hsync = var->hsync_len * bpp / 4; - hback = var->left_margin * bpp / 4; - - if (var->vmode & FB_VMODE_DOUBLE) - { - yres = var->yres * 2; - vfront = var->lower_margin * 2; - vsync = var->vsync_len * 2; - vback = var->upper_margin * 2; - } - else if (var->vmode & FB_VMODE_INTERLACED) - { - yres = (var->yres + 1) / 2; - vfront = (var->lower_margin + 1) / 2; - vsync = (var->vsync_len + 1) / 2; - vback = (var->upper_margin + 1) / 2; - } - else - { - yres = var->yres; /* -1 ? */ - vfront = var->lower_margin; - vsync = var->vsync_len; - vback = var->upper_margin; - } - - data.h_total = (hback / 8) + (xres / 8) - + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; - data.h_dispend = ((xres + bpp - 1)/ 8) - 1; - data.h_bstart = xres / 8 /* + 1 */; - - data.h_bstop = data.h_total+1 + 2 + 1; - data.h_sstart = (xres / 8) + (hfront / 8) + 1; - data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; - - data.v_total = yres + vfront + vsync + vback - 1; - - data.v_dispend = yres - 1; - data.v_bstart = yres; - - data.v_bstop = data.v_total; - data.v_sstart = yres + vfront - 1 - 2; - data.v_sstop = yres + vfront + vsync - 1; - -#if 0 /* testing */ - - printk("HBS: %i\n", data.h_bstart); - printk("HSS: %i\n", data.h_sstart); - printk("HSE: %i\n", data.h_sstop); - printk("HBE: %i\n", data.h_bstop); - printk("HT: %i\n", data.h_total); - - printk("hsync: %i\n", hsync); - printk("hfront: %i\n", hfront); - printk("hback: %i\n", hback); - - printk("VBS: %i\n", data.v_bstart); - printk("VSS: %i\n", data.v_sstart); - printk("VSE: %i\n", data.v_sstop); - printk("VBE: %i\n", data.v_bstop); - printk("VT: %i\n", data.v_total); - - printk("vsync: %i\n", vsync); - printk("vfront: %i\n", vfront); - printk("vback: %i\n", vback); -#endif - - if (data.v_total >= 1024) - printk("MAYDAY: v_total >= 1024; bailing out!\n"); - - reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); - reg_w(GREG_FEATURE_CONTROL_W, 0x00); - - seq_w(SEQ_RESET, 0x00); - seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ - - /* - * CLOCKING_MODE bits: - * 2: This one is only set for certain text-modes, wonder if - * it may be for EGA-lines? (it was referred to as CLKDIV2) - * (The CL drivers sets it to 0x21 with the comment: - * FullBandwidth (video off) and 8/9 dot clock) - */ - seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); - - seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ - seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ - seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ - seq_w(SEQ_RESET, 0x01); - seq_w(SEQ_RESET, 0x03); - - seq_w(SEQ_EXTENDED_ENABLE, 0x05); - - seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_LINEAR_0, 0x4a); - seq_w(SEQ_LINEAR_1, 0x00); - - seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); - seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); - seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); - - /* - * The lower 4 bits (0-3) are used to set the font-width for - * text-mode - DON'T try to set this for gfx-mode. - */ - seq_w(SEQ_EXT_CLOCK_MODE, 0x10); - seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); - - /* - * Extended Pixel Control: - * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) - * bit 1: (Packed/Nibble Pixel Format ?) - * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp - */ - seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); - - seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); - seq_w(SEQ_COLOR_EXP_WFG, 0x01); - seq_w(SEQ_COLOR_EXP_WBG, 0x00); - seq_w(SEQ_EXT_RW_CONTROL, 0x00); - seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); - seq_w(SEQ_COLOR_KEY_CNTL, 0x40); - seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); - seq_w(SEQ_CRC_CONTROL, 0x00); - seq_w(SEQ_PERF_SELECT, 0x10); - seq_w(SEQ_ACM_APERTURE_1, 0x00); - seq_w(SEQ_ACM_APERTURE_2, 0x30); - seq_w(SEQ_ACM_APERTURE_3, 0x00); - seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); - - - /* unlock register CRT0..CRT7 */ - crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); - - /* Zuerst zu schreibende Werte nur per printk ausgeben */ - DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); - crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); - - DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); - crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); - - DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); - crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); - - DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); - crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); - - DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); - crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); - - tmp = (data.h_sstop & 0x1f); - if (data.h_bstop & 0x20) - tmp |= 0x80; - DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); - crt_w(CRT_END_HOR_RETR, tmp); - - DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); - crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); - - tmp = 0x10; /* LineCompare bit #9 */ - if (data.v_total & 256) - tmp |= 0x01; - if (data.v_dispend & 256) - tmp |= 0x02; - if (data.v_sstart & 256) - tmp |= 0x04; - if (data.v_bstart & 256) - tmp |= 0x08; - if (data.v_total & 512) - tmp |= 0x20; - if (data.v_dispend & 512) - tmp |= 0x40; - if (data.v_sstart & 512) - tmp |= 0x80; - DEBUG printk("CRT_OVERFLOW: %d\n", tmp); - crt_w(CRT_OVERFLOW, tmp); - - crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ - - tmp = 0x40; /* LineCompare bit #8 */ - if (data.v_bstart & 512) - tmp |= 0x20; - if (var->vmode & FB_VMODE_DOUBLE) - tmp |= 0x80; - DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); - crt_w(CRT_MAX_SCAN_LINE, tmp); - - crt_w(CRT_CURSOR_START, 0x00); - crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ - - crt_w(CRT_START_ADDR_HIGH, 0x00); - crt_w(CRT_START_ADDR_LOW, 0x00); - - crt_w(CRT_CURSOR_LOC_HIGH, 0x00); - crt_w(CRT_CURSOR_LOC_LOW, 0x00); - - DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); - crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); - -#if 1 - /* 5 refresh cycles per scanline */ - DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); -#else - DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); -#endif - DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); - crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); - - DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); - crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); - - DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); - crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); - - DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); - crt_w(CRT_MODE_CONTROL, 0xe3); - - DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); - crt_w(CRT_LINE_COMPARE, 0xff); - - tmp = (var->xres_virtual / 8) * (bpp / 8); - crt_w(CRT_OFFSET, tmp); - - crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ - - tmp = 0x20; /* Enable extended end bits */ - if (data.h_total & 0x100) - tmp |= 0x01; - if ((data.h_dispend) & 0x100) - tmp |= 0x02; - if (data.h_bstart & 0x100) - tmp |= 0x04; - if (data.h_sstart & 0x100) - tmp |= 0x08; - if (var->vmode & FB_VMODE_INTERLACED) - tmp |= 0x10; - DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); - crt_w(CRT_EXT_HOR_TIMING1, tmp); - - tmp = 0x00; - if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) - tmp |= 0x10; - crt_w(CRT_EXT_START_ADDR, tmp); - - tmp = 0x00; - if (data.h_total & 0x200) - tmp |= 0x01; - if ((data.h_dispend) & 0x200) - tmp |= 0x02; - if (data.h_bstart & 0x200) - tmp |= 0x04; - if (data.h_sstart & 0x200) - tmp |= 0x08; - tmp |= ((data.h_bstop & 0xc0) >> 2); - tmp |= ((data.h_sstop & 0x60) << 1); - crt_w(CRT_EXT_HOR_TIMING2, tmp); - DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); - - tmp = 0x10; /* Line compare bit 10 */ - if (data.v_total & 0x400) - tmp |= 0x01; - if ((data.v_dispend) & 0x400) - tmp |= 0x02; - if (data.v_bstart & 0x400) - tmp |= 0x04; - if (data.v_sstart & 0x400) - tmp |= 0x08; - tmp |= ((data.v_bstop & 0x300) >> 3); - if (data.v_sstop & 0x10) - tmp |= 0x80; - crt_w(CRT_EXT_VER_TIMING, tmp); - DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); - - crt_w(CRT_MONITOR_POWER, 0x00); - - /* - * Convert from ps to Hz. - */ - freq_f = (1.0/(float)var->pixclock) * 1000000000; - freq = ((long)freq_f) * 1000; - - best_freq = find_fq(freq); - pll_w(0x02, best_freq); - best_freq = find_fq(61000000); - pll_w(0x0a, best_freq); - pll_w(0x0e, 0x22); - - gfx_w(GFX_SET_RESET, 0x00); - gfx_w(GFX_ENABLE_SET_RESET, 0x00); - gfx_w(GFX_COLOR_COMPARE, 0x00); - gfx_w(GFX_DATA_ROTATE, 0x00); - gfx_w(GFX_READ_MAP_SELECT, 0x00); - gfx_w(GFX_GRAPHICS_MODE, 0x00); - gfx_w(GFX_MISC, 0x05); - gfx_w(GFX_COLOR_XCARE, 0x0f); - gfx_w(GFX_BITMASK, 0xff); - - reg_r(ACT_ADDRESS_RESET); - attr_w(ACT_PALETTE0 , 0x00); - attr_w(ACT_PALETTE1 , 0x01); - attr_w(ACT_PALETTE2 , 0x02); - attr_w(ACT_PALETTE3 , 0x03); - attr_w(ACT_PALETTE4 , 0x04); - attr_w(ACT_PALETTE5 , 0x05); - attr_w(ACT_PALETTE6 , 0x06); - attr_w(ACT_PALETTE7 , 0x07); - attr_w(ACT_PALETTE8 , 0x08); - attr_w(ACT_PALETTE9 , 0x09); - attr_w(ACT_PALETTE10, 0x0a); - attr_w(ACT_PALETTE11, 0x0b); - attr_w(ACT_PALETTE12, 0x0c); - attr_w(ACT_PALETTE13, 0x0d); - attr_w(ACT_PALETTE14, 0x0e); - attr_w(ACT_PALETTE15, 0x0f); - reg_r(ACT_ADDRESS_RESET); - - attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ - - attr_w(ACT_OVERSCAN_COLOR, 0x00); - attr_w(ACT_COLOR_PLANE_ENA, 0x0f); - attr_w(ACT_HOR_PEL_PANNING, 0x00); - attr_w(ACT_COLOR_SELECT, 0x00); - - reg_r(ACT_ADDRESS_RESET); - reg_w(ACT_DATA, 0x20); - - reg_w(VDAC_MASK, 0xff); - - /* - * Extended palette adressing ??? - */ - switch (bpp){ - case 8: - reg_w(0x83c6, 0x00); - break; - case 16: - reg_w(0x83c6, 0x60); - break; - case 24: - reg_w(0x83c6, 0xe0); - break; - default: - printk("Illegal color-depth: %i\n", bpp); - } - - reg_w(VDAC_ADDRESS, 0x00); - - seq_w(SEQ_MAP_MASK, 0x0f ); - - return 0; -} - -/* - * Initialization - * - * Set the default video mode for this chipset. If a video mode was - * specified on the command line, it will override the default mode. - */ - -static int retz3_init(void) -{ - int i; -#if 0 - volatile unsigned long *CursorBase; -#endif - unsigned long board_addr, board_size; - struct ConfigDev *cd; - - cd = zorro_get_board (z3_key); - zorro_config_board (z3_key, 0); - board_addr = (unsigned long)cd->cd_BoardAddr; - board_size = (unsigned long)cd->cd_BoardSize; - - for (i = 0; i < 256; i++){ - for (i = 0; i < 256; i++){ - retz3_color_table [i][0] = i; - retz3_color_table [i][1] = i; - retz3_color_table [i][2] = i; - retz3_color_table [i][3] = 0; - } - } - - *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - - z3_mem = kernel_map (board_addr, board_size, - KERNELMAP_NOCACHE_SER, memstart); - - z3_regs = (char*) z3_mem; - z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; - - /* Get memory size - for now we asume its a 4MB board */ - - z3_size = 0x00400000; /* 4 MB */ - - memset ((char*)z3_fbmem, 0, z3_size); - - /* Disable hardware cursor */ - - seq_w(SEQ_CURSOR_Y_INDEX, 0x00); - - -#if 0 - /* Initialize hardware cursor */ - CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); - for (i=0; i < 8; i++){ - *(CursorBase +(i*4)) = 0xffffff00; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } - for (i=8; i < 64; i++){ - *(CursorBase +(i*4)) = 0xffff0000; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } -#endif - - retz3_setcolreg (255, 56, 100, 160, 0); - retz3_setcolreg (254, 0, 0, 0, 0); - - return 0; -} - - -/* - * This function should fill in the `fix' structure based on the - * values in the `par' structure. - */ - -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, - struct retz3_fb_par *par) -{ - int i; - - strcpy(fix->id, retz3_fb_name); - fix->smem_start = z3_fbmem; - fix->smem_len = z3_size; - - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - if (par->bpp == 8) - fix->visual = FB_VISUAL_PSEUDOCOLOR; - else - fix->visual = FB_VISUAL_DIRECTCOLOR; - - fix->xpanstep = 0; - fix->ypanstep = 0; - fix->ywrapstep = 0; - fix->line_length = 0; - - for (i = 0; i < arraysize(fix->reserved); i++) - fix->reserved[i] = 0; - - return 0; -} - - -/* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ - -static int retz3_decode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - par->xres = var->xres; - par->yres = var->yres; - par->xres_vir = var->xres_virtual; - par->yres_vir = var->yres_virtual; - par->bpp = var->bits_per_pixel; - par->pixclock = var->pixclock; - par->vmode = var->vmode; - - par->red = var->red; - par->green = var->green; - par->blue = var->blue; - par->transp = var->transp; - - par->left_margin = var->left_margin; - par->right_margin = var->right_margin; - par->upper_margin = var->upper_margin; - par->lower_margin = var->lower_margin; - par->hsync_len = var->hsync_len; - par->vsync_len = var->vsync_len; - - return 0; -} - - -/* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ - -static int retz3_encode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - int i; - - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->xres_vir; - var->yres_virtual = par->yres_vir; - var->xoffset = 0; - var->yoffset = 0; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - var->red = par->red; - var->green = par->green; - var->blue = par->blue; - var->transp = par->transp; - - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->accel = FB_ACCEL_RETINAZ3; - - var->pixclock = par->pixclock; - - var->sync = 0; /* ??? */ - var->left_margin = par->left_margin; - var->right_margin = par->right_margin; - var->upper_margin = par->upper_margin; - var->lower_margin = par->lower_margin; - var->hsync_len = par->hsync_len; - var->vsync_len = par->vsync_len; - - for (i = 0; i < arraysize(var->reserved); i++) - var->reserved[i] = 0; - - var->vmode = par->vmode; - return 0; -} - - -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp) -{ - /* We'll get to this */ - - if (regno > 255) - return 1; - - retz3_color_table [regno][0] = red & 0xff; - retz3_color_table [regno][1] = green & 0xff; - retz3_color_table [regno][2] = blue & 0xff; - retz3_color_table [regno][3] = transp; - - reg_w(VDAC_ADDRESS_W, regno); - reg_w(VDAC_DATA, (red & 0xff) >> 2); - reg_w(VDAC_DATA, (green & 0xff) >> 2); - reg_w(VDAC_DATA, (blue & 0xff) >> 2); - - return 0; -} - - -/* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ - -static int retz3_getcolreg(unsigned int regno, unsigned int *red, - unsigned int *green, unsigned int *blue, - unsigned int *transp) -{ - if (regno > 255) - return 1; - *red = retz3_color_table [regno][0]; - *green = retz3_color_table [regno][1]; - *blue = retz3_color_table [regno][2]; - *transp = retz3_color_table [regno][3]; - return 0; -} - - -/* - * (Un)Blank the screen - */ - -void retz3_blank(int blank) -{ - int i; - - if (blank) - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - } - else - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); - } -} - - -void retz3_bitblt (struct fb_var_screeninfo *var, - unsigned short srcx, unsigned short srcy, unsigned - short destx, unsigned short desty, unsigned short - width, unsigned short height, unsigned short cmd, - unsigned short mask) -{ - - volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); - unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); - - unsigned short mod; - unsigned long tmp; - unsigned long pat, src, dst; - unsigned char blt_status; - - int i, xres_virtual = var->xres_virtual; - short bpp = (var->bits_per_pixel & 0xff); - - if (bpp < 8) - bpp = 8; - - tmp = mask | (mask << 16); - -#if 0 - /* - * Check for blitter finished before we start messing with the - * pattern. - */ - do{ - blt_status = *(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)); - }while ((blt_status & 1) == 0); -#endif - - i = 0; - do{ - *pattern++ = tmp; - }while(i++ < bpp/4); - - tmp = cmd << 8; - *(acm + ACM_RASTEROP_ROTATION/4) = tmp; - - mod = 0xc0c2; - - pat = 8 * PAT_MEM_OFF; - dst = bpp * (destx + desty * xres_virtual); - - /* - * Source is not set for clear. - */ - if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { - src = bpp * (srcx + srcy * xres_virtual); - - if (destx > srcx) { - mod &= ~0x8000; - src += bpp * (width - 1); - dst += bpp * (width - 1); - pat += bpp * 2; - } - if (desty > srcy) { - mod &= ~0x4000; - src += bpp * (height - 1) * xres_virtual; - dst += bpp * (height - 1) * xres_virtual; - pat += bpp * 4; - } - - *(acm + ACM_SOURCE/4) = cpu_to_le32(src); - } - - *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); - - *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); - - tmp = mod << 16; - *(acm + ACM_CONTROL/4) = tmp; - - tmp = width | (height << 16); - - *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); - - *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; - *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; - - /* - * No reason to wait for the blitter to finish, it is better - * just to check if it has finished before we use it again. - */ -#if 1 -#if 0 - while ((*(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)) & 1) == 0); -#else - do{ - blt_status = *(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)); - } - while ((blt_status & 1) == 0); -#endif -#endif -} +#include <linux/init.h> -#if 0 -void retz3_fill (unsigned short x, unsigned short y, unsigned - short width, unsigned short height, - unsigned short mode, unsigned short color) -{ - -} -#endif - - -/************************************************************** - * Move cursor to x, y - */ -void retz3_MoveCursor (unsigned short x, unsigned short y) -{ - /* Guess we gotta deal with the cursor at some point */ -} - - -/* -------------------- Interfaces to hardware functions -------------------- */ - - -static struct fb_hwswitch retz3_switch = { - retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, - retz3_getcolreg, retz3_setcolreg, retz3_blank -}; - - -/* -------------------- Generic routines ------------------------------------ */ - - -/* - * Fill the hardware's `par' structure. - */ - -static void retz3_fb_get_par(struct retz3_fb_par *par) -{ - if (current_par_valid) - *par = current_par; - else - fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par); -} - - -static void retz3_fb_set_par(struct retz3_fb_par *par) -{ - current_par = *par; - current_par_valid = 1; -} - - -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) -{ - int err, activate; - struct retz3_fb_par par; - - if ((err = fbhw->decode_var(var, &par))) - return err; - activate = var->activate; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) - retz3_fb_set_par(&par); - fbhw->encode_var(var, &par); - var->activate = activate; - -#if 1 - retz3_set_video(var, ¤t_par); -#endif - return 0; -} - - -/* - * Default Colormaps - */ - -static unsigned short red16[] = - { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, - 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }; -static unsigned short green16[] = - { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000, - 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }; -static unsigned short blue16[] = - { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, - 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff }; - - -static struct fb_cmap default_16_colors = - { 0, 16, red16, green16, blue16, NULL }; - - -static struct fb_cmap *get_default_colormap(int bpp) -{ - return &default_16_colors; -} - - -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) -#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ - ((1<<(width))-1)) : 0)) - -static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc) -{ - int i, start; - unsigned short *red, *green, *blue, *transp; - unsigned int hred, hgreen, hblue, htransp; - - red = cmap->red; - green = cmap->green; - blue = cmap->blue; - transp = cmap->transp; - start = cmap->start; - - if (start < 0) - return -EINVAL; - for (i = 0; i < cmap->len; i++) { - if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) - return 0; - hred = CNVT_FROMHW(hred, var->red.length); - hgreen = CNVT_FROMHW(hgreen, var->green.length); - hblue = CNVT_FROMHW(hblue, var->blue.length); - htransp = CNVT_FROMHW(htransp, var->transp.length); - if (kspc) { - *red = hred; - *green = hgreen; - *blue = hblue; - if (transp) - *transp = htransp; - } else { - put_user(hred, red); - put_user(hgreen, green); - put_user(hblue, blue); - if (transp) - put_user(htransp, transp); - } - red++; - green++; - blue++; - if (transp) - transp++; - } - return 0; -} - - -static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc) -{ - int i, start; - unsigned short *red, *green, *blue, *transp; - unsigned int hred, hgreen, hblue, htransp; - - red = cmap->red; - green = cmap->green; - blue = cmap->blue; - transp = cmap->transp; - start = cmap->start; - - if (start < 0) - return -EINVAL; - for (i = 0; i < cmap->len; i++) { - if (kspc) { - hred = *red; - hgreen = *green; - hblue = *blue; - htransp = transp ? *transp : 0; - } else { - get_user(hred, red); - get_user(hgreen, green); - get_user(hblue, blue); - if (transp) - get_user(htransp, transp); - else - htransp = 0; - } - hred = CNVT_TOHW(hred, var->red.length); - hgreen = CNVT_TOHW(hgreen, var->green.length); - hblue = CNVT_TOHW(hblue, var->blue.length); - htransp = CNVT_TOHW(htransp, var->transp.length); - red++; - green++; - blue++; - if (transp) - transp++; - if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) - return 0; - } - return 0; -} - - -static void do_install_cmap(int con) -{ - if (con != currcon) - return; - if (disp[con].cmap.len) - do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1); - else - do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel), - &disp[con].var, 1); -} - - -static void memcpy_fs(int fsfromto, void *to, void *from, int len) -{ - switch (fsfromto) { - case 0: - memcpy(to, from, len); - return; - case 1: - copy_from_user(to, from, len); - return; - case 2: - copy_to_user(to, from, len); - return; - } -} - - -static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) -{ - int size; - int tooff = 0, fromoff = 0; - - if (to->start > from->start) - fromoff = to->start-from->start; - else - tooff = from->start-to->start; - size = to->len-tooff; - if (size > from->len-fromoff) - size = from->len-fromoff; - if (size < 0) - return; - size *= sizeof(unsigned short); - memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); - memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); - memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); - if (from->transp && to->transp) - memcpy_fs(fsfromto, to->transp+tooff, - from->transp+fromoff, size); -} - - -static int alloc_cmap(struct fb_cmap *cmap, int len, int transp) -{ - int size = len*sizeof(unsigned short); - - if (cmap->len != len) { - if (cmap->red) - kfree(cmap->red); - if (cmap->green) - kfree(cmap->green); - if (cmap->blue) - kfree(cmap->blue); - if (cmap->transp) - kfree(cmap->transp); - cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; - cmap->len = 0; - if (!len) - return 0; - if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) - return -1; - if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) - return -1; - if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) - return -1; - if (transp) { - if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) - return -1; - } else - cmap->transp = NULL; - } - cmap->start = 0; - cmap->len = len; - copy_cmap(get_default_colormap(len), cmap, 0); - return 0; -} - - -/* - * Get the Fixed Part of the Display - */ - -static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con) -{ - struct retz3_fb_par par; - int error = 0; - - if (con == -1) - retz3_fb_get_par(&par); - else - error = fbhw->decode_var(&disp[con].var, &par); - return(error ? error : fbhw->encode_fix(fix, &par)); -} - - -/* - * Get the User Defined Part of the Display - */ - -static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con) -{ - struct retz3_fb_par par; - int error = 0; - - if (con == -1) { - retz3_fb_get_par(&par); - error = fbhw->encode_var(var, &par); - } else - *var = disp[con].var; - return error; -} - - -static void retz3_fb_set_disp(int con) -{ - struct fb_fix_screeninfo fix; - - retz3_fb_get_fix(&fix, con); - if (con == -1) - con = 0; - disp[con].screen_base = (unsigned char *)fix.smem_start; - disp[con].visual = fix.visual; - disp[con].type = fix.type; - disp[con].type_aux = fix.type_aux; - disp[con].ypanstep = fix.ypanstep; - disp[con].ywrapstep = fix.ywrapstep; - disp[con].can_soft_blank = 1; - disp[con].inverse = z3fb_inverse; -} - - -/* - * Set the User Defined Part of the Display - */ - -static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con) -{ - int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; - - if ((err = do_fb_set_var(var, con == currcon))) - return err; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres = disp[con].var.xres; - oldyres = disp[con].var.yres; - oldvxres = disp[con].var.xres_virtual; - oldvyres = disp[con].var.yres_virtual; - oldbpp = disp[con].var.bits_per_pixel; - disp[con].var = *var; - if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || - oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel) { - retz3_fb_set_disp(con); - (*fb_info.changevar)(con); - alloc_cmap(&disp[con].cmap, 0, 0); - do_install_cmap(con); - } - } - var->activate = 0; - return 0; -} - - -/* - * Get the Colormap - */ - -static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) -{ - if (con == currcon) /* current console? */ - return(do_fb_get_cmap(cmap, &disp[con].var, kspc)); - else if (disp[con].cmap.len) /* non default colormap? */ - copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); - else - copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); - return 0; -} - - -/* - * Set the Colormap - */ - -static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) -{ - int err; - - if (!disp[con].cmap.len) { /* no colormap allocated? */ - if ((err = alloc_cmap(&disp[con].cmap, - 1<<disp[con].var.bits_per_pixel, 0))) - return err; - } - if (con == currcon) /* current console? */ - return(do_fb_set_cmap(cmap, &disp[con].var, kspc)); - else - copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1); - return 0; -} - - -/* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con) -{ - return -EINVAL; -} - - -/* - * RetinaZ3 Frame Buffer Specific ioctls - */ - -static int retz3_fb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con) -{ - return -EINVAL; -} - - -static struct fb_ops retz3_fb_ops = { - retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap, - retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl -}; - - -int retz3_probe(void) -{ - z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0); - return(z3_key); -} - - -void retz3_video_setup(char *options, int *ints) -{ - char *this_opt; - int i; - - fb_info.fontname[0] = '\0'; - - if (!options || !*options) - return; - - for (this_opt = strtok(options, ","); this_opt; - this_opt = strtok(NULL, ",")){ - if (!strcmp(this_opt, "inverse")) { - z3fb_inverse = 1; - for (i = 0; i < 16; i++) { - red16[i] = ~red16[i]; - green16[i] = ~green16[i]; - blue16[i] = ~blue16[i]; - } - } else if (!strncmp(this_opt, "font:", 5)) - strcpy(fb_info.fontname, this_opt+5); - else - z3fb_mode = get_video_mode(this_opt); - } -} - - -/* - * Initialization - */ - -struct fb_info *retz3_fb_init(long *mem_start) -{ - int err; - struct retz3_fb_par par; - - memstart = mem_start; - - fbhw = &retz3_switch; - - err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops, - NUM_TOTAL_MODES, retz3_fb_predefined); - if (err < 0) - panic("Cannot register frame buffer\n"); - - fbhw->init(); - - if (z3fb_mode == -1) - z3fb_mode = 1; - - fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par); - fbhw->encode_var(&retz3_fb_predefined[0], &par); - - strcpy(fb_info.modename, retz3_fb_name); - fb_info.disp = disp; - fb_info.switch_con = &z3fb_switch; - fb_info.updatevar = &z3fb_updatevar; - fb_info.blank = &z3fb_blank; - fb_info.setcmap = &z3fb_setcmap; - - do_fb_set_var(&retz3_fb_predefined[0], 0); - retz3_fb_get_var(&disp[0].var, -1); - retz3_fb_set_disp(-1); - do_install_cmap(0); - - return &fb_info; -} - - -static int z3fb_switch(int con) -{ - /* Do we have to save the colormap? */ - if (disp[currcon].cmap.len) - do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1); - - do_fb_set_var(&disp[con].var, 1); - currcon = con; - /* Install new colormap */ - do_install_cmap(con); - return 0; -} - - -/* - * Update the `var' structure (called by fbcon.c) - * - * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. - * Since it's called by a kernel driver, no range checking is done. - */ - -static int z3fb_updatevar(int con) -{ - return 0; -} - - -/* - * Blank the display. - */ - -static void z3fb_blank(int blank) -{ - fbhw->blank(blank); -} - - -/* - * Set the colormap - */ - -static int z3fb_setcmap(struct fb_cmap *cmap, int con) -{ - return(retz3_fb_set_cmap(cmap, 1, con)); -} - - -/* - * Get a Video Mode - */ - -static int get_video_mode(const char *name) -{ - int i; - - for (i = 1; i <= NUM_PREDEF_MODES; i++) - if (!strcmp(name, retz3_fb_modenames[i])){ - retz3_fb_predefined[0] = retz3_fb_predefined[i]; - return i; - } - return -1; -} -/* - * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the - * RetinaZ3 frame buffer device - * - * Copyright (C) 1997 Jes Sorensen - * - * This file is based on the CyberVision64 frame buffer device and - * the generic Cirrus Logic driver. - * - * cyberfb.c: Copyright (C) 1996 Martin Apel, - * Geert Uytterhoeven - * clgen.c: Copyright (C) 1996 Frank Neumann - * - * History: - * - 22 Jan 97: Initial work - * - 14 Feb 97: Screen initialization works somewhat, still only - * 8-bit packed pixel is supported. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/malloc.h> -#include <linux/delay.h> -#include <linux/fb.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/irq.h> -#include <linux/zorro.h> #include <asm/pgtable.h> #include "retz3fb.h" @@ -3402,7 +1652,7 @@ void retz3_video_setup(char *options, int *ints) * Initialization */ -struct fb_info *retz3_fb_init(long *mem_start) +__initfunc(struct fb_info *retz3_fb_init(long *mem_start)) { int err; struct retz3_fb_par par; diff --git a/arch/m68k/amiga/retz3fb.h b/arch/m68k/amiga/retz3fb.h index 9ff209060..0cb03c324 100644 --- a/arch/m68k/amiga/retz3fb.h +++ b/arch/m68k/amiga/retz3fb.h @@ -284,289 +284,3 @@ #define Z3BLTorInverted 0xb0 /* NOT src OR dst */ #define Z3BLTnand 0x70 /* NOT src OR NOT dst */ #define Z3BLTset 0xf0 /* 1 */ -/* - * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the - * RetinaZ3 frame buffer device - * - * Copyright (C) 1997 Jes Sorensen - * - * History: - * - 22 Jan 97: Initial work - * - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -/* - * Macros to read and write to registers. - */ -#define reg_w(reg,dat) (*(z3_regs + reg) = dat) -#define reg_r(reg) (*(z3_regs + reg)) - -/* - * Macro to access the sequencer. - */ -#define seq_w(sreg,sdat) \ - do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) - -/* - * Macro to access the CRT controller. - */ -#define crt_w(creg,cdat) \ - do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) - -/* - * Macro to access the graphics controller. - */ -#define gfx_w(greg,gdat) \ - do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) - -/* - * Macro to access the attribute controller. - */ -#define attr_w(areg,adat) \ - do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) - -/* - * Macro to access the pll. - */ -#define pll_w(preg,pdat) \ - do{ reg_w(PLL_IDX, preg); \ - reg_w(PLL_DATA, (pdat & 0xff)); \ - reg_w(PLL_DATA, (pdat >> 8));\ - } while(0) - -/* - * Offsets - */ -#define VIDEO_MEM_OFFSET 0x00c00000 -#define ACM_OFFSET 0x00b00000 - -/* - * Accelerator Control Menu - */ -#define ACM_PRIMARY_OFFSET 0x00 -#define ACM_SECONDARY_OFFSET 0x04 -#define ACM_MODE_CONTROL 0x08 -#define ACM_CURSOR_POSITION 0x0c -#define ACM_START_STATUS 0x30 -#define ACM_CONTROL 0x34 -#define ACM_RASTEROP_ROTATION 0x38 -#define ACM_BITMAP_DIMENSION 0x3c -#define ACM_DESTINATION 0x40 -#define ACM_SOURCE 0x44 -#define ACM_PATTERN 0x48 -#define ACM_FOREGROUND 0x4c -#define ACM_BACKGROUND 0x50 - -/* - * Video DAC addresses - */ -#define VDAC_ADDRESS 0x03c8 -#define VDAC_ADDRESS_W 0x03c8 -#define VDAC_ADDRESS_R 0x03c7 -#define VDAC_STATE 0x03c7 -#define VDAC_DATA 0x03c9 -#define VDAC_MASK 0x03c6 - -/* - * Sequencer - */ -#define SEQ_IDX 0x03c4 /* Sequencer Index */ -#define SEQ_DATA 0x03c5 -#define SEQ_RESET 0x00 -#define SEQ_CLOCKING_MODE 0x01 -#define SEQ_MAP_MASK 0x02 -#define SEQ_CHAR_MAP_SELECT 0x03 -#define SEQ_MEMORY_MODE 0x04 -#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ -#define SEQ_UNKNOWN1 0x06 -#define SEQ_UNKNOWN2 0x07 -#define SEQ_CHIP_ID 0x08 -#define SEQ_UNKNOWN3 0x09 -#define SEQ_CURSOR_COLOR1 0x0a -#define SEQ_CURSOR_COLOR0 0x0b -#define SEQ_CURSOR_CONTROL 0x0c -#define SEQ_CURSOR_X_LOC_HI 0x0d -#define SEQ_CURSOR_X_LOC_LO 0x0e -#define SEQ_CURSOR_Y_LOC_HI 0x0f -#define SEQ_CURSOR_Y_LOC_LO 0x10 -#define SEQ_CURSOR_X_INDEX 0x11 -#define SEQ_CURSOR_Y_INDEX 0x12 -#define SEQ_CURSOR_STORE_HI 0x13 -#define SEQ_CURSOR_STORE_LO 0x14 -#define SEQ_CURSOR_ST_OFF_HI 0x15 -#define SEQ_CURSOR_ST_OFF_LO 0x16 -#define SEQ_CURSOR_PIXELMASK 0x17 -#define SEQ_PRIM_HOST_OFF_HI 0x18 -#define SEQ_PRIM_HOST_OFF_LO 0x19 -#define SEQ_LINEAR_0 0x1a -#define SEQ_LINEAR_1 0x1b -#define SEQ_SEC_HOST_OFF_HI 0x1c -#define SEQ_SEC_HOST_OFF_LO 0x1d -#define SEQ_EXTENDED_MEM_ENA 0x1e -#define SEQ_EXT_CLOCK_MODE 0x1f -#define SEQ_EXT_VIDEO_ADDR 0x20 -#define SEQ_EXT_PIXEL_CNTL 0x21 -#define SEQ_BUS_WIDTH_FEEDB 0x22 -#define SEQ_PERF_SELECT 0x23 -#define SEQ_COLOR_EXP_WFG 0x24 -#define SEQ_COLOR_EXP_WBG 0x25 -#define SEQ_EXT_RW_CONTROL 0x26 -#define SEQ_MISC_FEATURE_SEL 0x27 -#define SEQ_COLOR_KEY_CNTL 0x28 -#define SEQ_COLOR_KEY_MATCH0 0x29 -#define SEQ_COLOR_KEY_MATCH1 0x2a -#define SEQ_COLOR_KEY_MATCH2 0x2b -#define SEQ_UNKNOWN6 0x2c -#define SEQ_CRC_CONTROL 0x2d -#define SEQ_CRC_DATA_LOW 0x2e -#define SEQ_CRC_DATA_HIGH 0x2f -#define SEQ_MEMORY_MAP_CNTL 0x30 -#define SEQ_ACM_APERTURE_1 0x31 -#define SEQ_ACM_APERTURE_2 0x32 -#define SEQ_ACM_APERTURE_3 0x33 -#define SEQ_BIOS_UTILITY_0 0x3e -#define SEQ_BIOS_UTILITY_1 0x3f - -/* - * Graphics Controller - */ -#define GFX_IDX 0x03ce -#define GFX_DATA 0x03cf -#define GFX_SET_RESET 0x00 -#define GFX_ENABLE_SET_RESET 0x01 -#define GFX_COLOR_COMPARE 0x02 -#define GFX_DATA_ROTATE 0x03 -#define GFX_READ_MAP_SELECT 0x04 -#define GFX_GRAPHICS_MODE 0x05 -#define GFX_MISC 0x06 -#define GFX_COLOR_XCARE 0x07 -#define GFX_BITMASK 0x08 - -/* - * CRT Controller - */ -#define CRT_IDX 0x03d4 -#define CRT_DATA 0x03d5 -#define CRT_HOR_TOTAL 0x00 -#define CRT_HOR_DISP_ENA_END 0x01 -#define CRT_START_HOR_BLANK 0x02 -#define CRT_END_HOR_BLANK 0x03 -#define CRT_START_HOR_RETR 0x04 -#define CRT_END_HOR_RETR 0x05 -#define CRT_VER_TOTAL 0x06 -#define CRT_OVERFLOW 0x07 -#define CRT_PRESET_ROW_SCAN 0x08 -#define CRT_MAX_SCAN_LINE 0x09 -#define CRT_CURSOR_START 0x0a -#define CRT_CURSOR_END 0x0b -#define CRT_START_ADDR_HIGH 0x0c -#define CRT_START_ADDR_LOW 0x0d -#define CRT_CURSOR_LOC_HIGH 0x0e -#define CRT_CURSOR_LOC_LOW 0x0f -#define CRT_START_VER_RETR 0x10 -#define CRT_END_VER_RETR 0x11 -#define CRT_VER_DISP_ENA_END 0x12 -#define CRT_OFFSET 0x13 -#define CRT_UNDERLINE_LOC 0x14 -#define CRT_START_VER_BLANK 0x15 -#define CRT_END_VER_BLANK 0x16 -#define CRT_MODE_CONTROL 0x17 -#define CRT_LINE_COMPARE 0x18 -#define CRT_UNKNOWN1 0x19 -#define CRT_UNKNOWN2 0x1a -#define CRT_UNKNOWN3 0x1b -#define CRT_UNKNOWN4 0x1c -#define CRT_UNKNOWN5 0x1d -#define CRT_UNKNOWN6 0x1e -#define CRT_UNKNOWN7 0x1f -#define CRT_UNKNOWN8 0x20 -#define CRT_UNKNOWN9 0x21 -#define CRT_UNKNOWN10 0x22 -#define CRT_UNKNOWN11 0x23 -#define CRT_UNKNOWN12 0x24 -#define CRT_UNKNOWN13 0x25 -#define CRT_UNKNOWN14 0x26 -#define CRT_UNKNOWN15 0x27 -#define CRT_UNKNOWN16 0x28 -#define CRT_UNKNOWN17 0x29 -#define CRT_UNKNOWN18 0x2a -#define CRT_UNKNOWN19 0x2b -#define CRT_UNKNOWN20 0x2c -#define CRT_UNKNOWN21 0x2d -#define CRT_UNKNOWN22 0x2e -#define CRT_UNKNOWN23 0x2f -#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ -#define CRT_EXT_START_ADDR 0x31 -#define CRT_EXT_HOR_TIMING2 0x32 -#define CRT_EXT_VER_TIMING 0x33 -#define CRT_MONITOR_POWER 0x34 - -/* - * General Registers - */ -#define GREG_STATUS0_R 0x03c2 -#define GREG_STATUS1_R 0x03da -#define GREG_MISC_OUTPUT_R 0x03cc -#define GREG_MISC_OUTPUT_W 0x03c2 -#define GREG_FEATURE_CONTROL_R 0x03ca -#define GREG_FEATURE_CONTROL_W 0x03da -#define GREG_POS 0x0102 - -/* - * Attribute Controller - */ -#define ACT_IDX 0x03C0 -#define ACT_ADDRESS_R 0x03C0 -#define ACT_DATA 0x03C0 -#define ACT_ADDRESS_RESET 0x03DA -#define ACT_PALETTE0 0x00 -#define ACT_PALETTE1 0x01 -#define ACT_PALETTE2 0x02 -#define ACT_PALETTE3 0x03 -#define ACT_PALETTE4 0x04 -#define ACT_PALETTE5 0x05 -#define ACT_PALETTE6 0x06 -#define ACT_PALETTE7 0x07 -#define ACT_PALETTE8 0x08 -#define ACT_PALETTE9 0x09 -#define ACT_PALETTE10 0x0A -#define ACT_PALETTE11 0x0B -#define ACT_PALETTE12 0x0C -#define ACT_PALETTE13 0x0D -#define ACT_PALETTE14 0x0E -#define ACT_PALETTE15 0x0F -#define ACT_ATTR_MODE_CNTL 0x10 -#define ACT_OVERSCAN_COLOR 0x11 -#define ACT_COLOR_PLANE_ENA 0x12 -#define ACT_HOR_PEL_PANNING 0x13 -#define ACT_COLOR_SELECT 0x14 - -/* - * PLL - */ -#define PLL_IDX 0x83c8 -#define PLL_DATA 0x83c9 - -/* - * Blitter operations - */ -#define Z3BLTclear 0x00 /* 0 */ -#define Z3BLTand 0x80 /* src AND dst */ -#define Z3BLTandReverse 0x40 /* src AND NOT dst */ -#define Z3BLTcopy 0xc0 /* src */ -#define Z3BLTandInverted 0x20 /* NOT src AND dst */ -#define Z3BLTnoop 0xa0 /* dst */ -#define Z3BLTxor 0x60 /* src XOR dst */ -#define Z3BLTor 0xe0 /* src OR dst */ -#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ -#define Z3BLTequiv 0x90 /* NOT src XOR dst */ -#define Z3BLTinvert 0x50 /* NOT dst */ -#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ -#define Z3BLTcopyInverted 0x30 /* NOT src */ -#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ -#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ -#define Z3BLTset 0xf0 /* 1 */ diff --git a/arch/m68k/amiga/zorro.c b/arch/m68k/amiga/zorro.c index acca3e6bc..d64ad8ce3 100644 --- a/arch/m68k/amiga/zorro.c +++ b/arch/m68k/amiga/zorro.c @@ -13,10 +13,11 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> +#include <linux/init.h> +#include <linux/zorro.h> #include <asm/setup.h> #include <asm/bitops.h> #include <asm/amigahw.h> -#include <linux/zorro.h> #ifdef CONFIG_ZORRO @@ -415,10 +416,6 @@ BEGIN_PROD(MASOBOSHI) PROD("MVD 819", MVD_819) END -BEGIN_PROD(DELACOMP) - PROD("RAM Expansion 2000", DELACOMP_RAM_2000) -END - BEGIN_PROD(VILLAGE_TRONIC) PROD("Domino Graphics Board (RAM)", DOMINO_RAM) PROD("Domino Graphics Board (REG)", DOMINO_REG) @@ -656,7 +653,6 @@ BEGIN_MANUF MANUF("Helfrich", HELFRICH1) MANUF("Software Result Enterprises", SW_RESULT_ENTS) MANUF("Masoboshi", MASOBOSHI) - MANUF("DelaComp", DELACOMP) MANUF("Village Tronic", VILLAGE_TRONIC) MANUF("Utilities Unlimited", UTILITIES_ULTD) MANUF("Amitrix", AMITRIX) @@ -992,7 +988,7 @@ static void mark_region(u_long addr, u_long size, int flag) * Initialization */ -void zorro_init(void) +__initfunc(void zorro_init(void)) { int i; struct ConfigDev *cd; diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c index 64c9a62d3..efa6fc8b8 100644 --- a/arch/m68k/atari/atafb.c +++ b/arch/m68k/atari/atafb.c @@ -46,6 +46,7 @@ #include <linux/tty.h> #include <linux/malloc.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/setup.h> #include <asm/uaccess.h> @@ -2911,8 +2912,8 @@ atafb_setcmap(struct fb_cmap *cmap, int con) return(atari_fb_set_cmap(cmap, 1, con)); } -struct fb_info * -atari_fb_init(long *mem_start) +__initfunc(struct fb_info * +atari_fb_init(long *mem_start)) { int err; int pad; diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index b65beefb1..b2887f7da 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -39,6 +39,7 @@ #include <linux/kernel.h> #include <linux/ptrace.h> #include <linux/kernel_stat.h> +#include <linux/init.h> #include <asm/system.h> #include <asm/traps.h> @@ -162,15 +163,19 @@ static int free_vme_vec_bitmap = 0; #define MFP_MK_BASE "0xfa13" -/* This must agree with head.S. */ -#define ORIG_DO "0x20" -#define FORMATVEC "0x2E" -#define SR "0x28" +/* This must agree with entry.S. */ +#define ORIG_DO "0x24" +#define FORMATVEC "0x32" +#define SR "0x2C" #define SAVE_ALL \ "clrl %%sp@-;" /* stk_adj */ \ "pea -1:w;" /* orig d0 = -1 */ \ "movel %%d0,%%sp@-;" /* d0 */ \ - "moveml %%d1-%%d5/%%a0-%%a1,%%sp@-" + "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-" +#define GET_CURRENT(tmp) \ + "movel %%sp,"#tmp";" \ + "andw #-8192,"#tmp";" \ + "movel "#tmp",%%a2" #define BUILD_SLOW_IRQ(n) \ asmlinkage void IRQ_NAME(n); \ @@ -180,6 +185,7 @@ __asm__ (ALIGN_STR "\n" \ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ " addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \ SAVE_ALL "\n" \ + GET_CURRENT(%%d0) "\n" \ " andb #~(1<<(" #n "&7))," /* mask this interrupt */ \ "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ " bfextu %%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \ @@ -282,7 +288,8 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": orw #0x700,%%sr /* disable all interrupts */ "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" - SAVE_ALL " + SAVE_ALL "\n" + GET_CURRENT(%%d0) " /* get vector number from stack frame and convert to source */ bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0 subw #(0x40-8),%%d0 @@ -331,7 +338,7 @@ extern void atari_microwire_cmd( int cmd ); * the atari IRQ handling routines. */ -void atari_init_IRQ(void) +__initfunc(void atari_init_IRQ(void)) { int i; diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 4f57cb928..beccf9a84 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -22,6 +22,7 @@ #include <linux/timer.h> #include <linux/kd.h> #include <linux/random.h> +#include <linux/init.h> #include <asm/atariints.h> #include <asm/atarihw.h> @@ -804,7 +805,7 @@ void atari_kbd_leds (unsigned int leds) * Martin Rogge, 20 Aug 1995 */ -int atari_keyb_init(void) +__initfunc(int atari_keyb_init(void)) { /* setup key map */ key_maps[0] = ataplain_map; diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 0d0607da0..3cc2a840a 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -32,6 +32,7 @@ #include <linux/tty.h> #include <linux/console.h> #include <linux/interrupt.h> +#include <linux/init.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -106,7 +107,7 @@ extern void (*kd_mksound)(unsigned int, unsigned int); * a temporary VBR and a vector table for the duration of the test. */ -static int hwreg_present( volatile void *regp ) +__initfunc(static int hwreg_present( volatile void *regp )) { int ret = 0; long save_sp, save_vbr; @@ -132,9 +133,8 @@ static int hwreg_present( volatile void *regp ) } #if 0 -static int hwreg_present_bywrite( volatile void *regp, - unsigned char val ) - +__initfunc(static int +hwreg_present_bywrite(volatile void *regp, unsigned char val)) { int ret; long save_sp, save_vbr; @@ -166,7 +166,7 @@ static int hwreg_present_bywrite( volatile void *regp, /* Basically the same, but writes a value into a word register, protected * by a bus error handler */ -static int hwreg_write( volatile void *regp, unsigned short val ) +__initfunc(static int hwreg_write( volatile void *regp, unsigned short val )) { int ret; long save_sp, save_vbr; @@ -201,7 +201,7 @@ static int hwreg_write( volatile void *regp, unsigned short val ) * should be readable without trouble (from channel A!). */ -static int scc_test( volatile char *ctla ) +__initfunc(static int scc_test( volatile char *ctla )) { if (!hwreg_present( ctla )) return( 0 ); @@ -228,7 +228,7 @@ static int scc_test( volatile char *ctla ) * Parse an Atari-specific record in the bootinfo */ -int atari_parse_bootinfo(const struct bi_record *record) +__initfunc(int atari_parse_bootinfo(const struct bi_record *record)) { int unknown = 0; const u_long *data = record->data; @@ -247,7 +247,7 @@ int atari_parse_bootinfo(const struct bi_record *record) * Setup the Atari configuration info */ -void config_atari(void) +__initfunc(void config_atari(void)) { memset(&atari_hw_present, 0, sizeof(atari_hw_present)); @@ -493,7 +493,8 @@ void config_atari(void) } } -static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +__initfunc(static void +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; @@ -976,7 +977,7 @@ static void atari_par_console_write (const char *str, unsigned int count) } -static void atari_debug_init(void) +__initfunc(static void atari_debug_init(void)) { #ifdef CONFIG_KGDB /* if the m68k_debug_device is used by the GDB stub, do nothing here */ diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c index de6014171..2e33b151f 100644 --- a/arch/m68k/atari/joystick.c +++ b/arch/m68k/atari/joystick.c @@ -11,6 +11,7 @@ #include <linux/errno.h> #include <linux/major.h> #include <linux/poll.h> +#include <linux/init.h> #include <asm/atarikb.h> #include <asm/atari_joystick.h> @@ -128,7 +129,7 @@ struct file_operations atari_joystick_fops = { release_joystick }; -int atari_joystick_init(void) +__initfunc(int atari_joystick_init(void)) { joystick[0].active = joystick[1].active = 0; joystick[0].ready = joystick[1].ready = 0; diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 247b9f684..9dc82de18 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -32,6 +32,8 @@ #include <linux/types.h> #include <linux/genhd.h> #include <linux/sched.h> +#include <linux/init.h> + #include <asm/atari_stdma.h> #include <asm/atariints.h> #include <asm/atarihw.h> @@ -171,7 +173,7 @@ int stdma_islocked(void) * */ -void stdma_init(void) +__initfunc(void stdma_init(void)) { stdma_isr = NULL; request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index 565b20535..4e5f57bc9 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -149,6 +149,7 @@ atari_stram_free (void *ptr) #else #include <linux/mm.h> +#include <linux/init.h> /* ++roman: * @@ -190,7 +191,7 @@ static unsigned long stram_end; /* Overall end of ST-Ram */ -void atari_stram_init( void ) +__initfunc(void atari_stram_init( void )) { int i; diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c index d35966686..23b7fa9d0 100644 --- a/arch/m68k/boot/amiga/linuxboot.c +++ b/arch/m68k/boot/amiga/linuxboot.c @@ -22,6 +22,8 @@ * for more details. * * History: + * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo + * interface version 1.0 (Geert) * 03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's * code for ataboot) * 30 Dec 1996 Reverted the CPU detection to the old scheme @@ -791,6 +793,7 @@ static u_long get_chipset(void) static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu) { *cpu = *fpu = 0; + if (SysBase->AttnFlags & AFF_68060) *cpu = CPU_68060; else if (SysBase->AttnFlags & AFF_68040) @@ -799,15 +802,15 @@ static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu) *cpu = CPU_68030; else if (SysBase->AttnFlags & AFF_68020) *cpu = CPU_68020; + if (*cpu == CPU_68040 || *cpu == CPU_68060) { if (SysBase->AttnFlags & AFF_FPU40) *fpu = *cpu; - } else { - if (SysBase->AttnFlags & AFF_68882) - *fpu = FPU_68882; - else if (SysBase->AttnFlags & AFF_68881) - *fpu = FPU_68881; - } + } else if (SysBase->AttnFlags & AFF_68882) + *fpu = FPU_68882; + else if (SysBase->AttnFlags & AFF_68881) + *fpu = FPU_68881; + *mmu = *cpu; } @@ -1047,7 +1050,7 @@ static int create_compat_bootinfo(void) compat_bootinfo.cputype |= COMPAT_FPU_68040; else if (bi.fputype & FPU_68060) compat_bootinfo.cputype |= COMPAT_FPU_68060; - else { + else if (bi.fputype) { Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype); return(0); } diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h index 8ebfe63b4..e04425a3a 100644 --- a/arch/m68k/boot/amiga/linuxboot.h +++ b/arch/m68k/boot/amiga/linuxboot.h @@ -31,7 +31,7 @@ * Amiboot Version */ -#define AMIBOOT_VERSION "5.4" +#define AMIBOOT_VERSION "5.5" /* diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 5768516bd..466cf3fbc 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -51,13 +51,23 @@ .include "fpsp.h" -LOFF_ORIG_D0 = 0x20 +/* + * This has to match entry.S + */ +LOFF_ORIG_D0 = 0x24 + +#define curptr a2 #define SAVE_ALL \ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1,%sp@- + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; + +#define GET_CURRENT(tmp) \ + movel %sp,tmp; \ + andw &-8192,tmp; \ + movel tmp,%curptr; |xref b1238_fix @@ -81,6 +91,7 @@ real_dz: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -175,6 +186,7 @@ inex_done: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -204,6 +216,7 @@ ovfl_done: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -233,6 +246,7 @@ unfl_done: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -258,6 +272,7 @@ real_snan: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -283,6 +298,7 @@ real_operr: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -314,6 +330,7 @@ real_bsun: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -338,6 +355,7 @@ real_fline: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -363,6 +381,7 @@ real_unsupp: movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -419,6 +438,7 @@ Lmustsched: SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall + GET_CURRENT(%d0) bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. @@ -497,7 +517,7 @@ user_read: movel %d0,-(%sp) movel %a1,-(%sp) movel %a0,-(%sp) - jsr copyin + jsr copyin addw #12,%sp movel (%sp)+,%d1 rts diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S index 5940a374a..3c310c237 100644 --- a/arch/m68k/ifpsp060/iskeleton.S +++ b/arch/m68k/ifpsp060/iskeleton.S @@ -36,13 +36,23 @@ #include <linux/linkage.h> -LOFF_ORIG_D0 = 0x20 +/* + * This has to match entry.S + */ +LOFF_ORIG_D0 = 0x24 + +#define curptr a2 #define SAVE_ALL \ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1,%sp@- + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; + +#define GET_CURRENT(tmp) \ + movel %sp,tmp; \ + andw &-8192,tmp; \ + movel tmp,%curptr; |################################ | (1) EXAMPLE CALL-OUTS # @@ -85,6 +95,7 @@ Lmustsched: SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall + GET_CURRENT(%d0) bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. | diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 2cb35e67f..ef5ef46d6 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -33,12 +33,13 @@ * 10(sp) - d5 * 14(sp) - a0 * 18(sp) - a1 - * 1C(sp) - d0 - * 20(sp) - orig_d0 - * 24(sp) - stack adjustment - * 28(sp) - sr - * 2A(sp) - pc - * 2E(sp) - format & vector + * 1C(sp) - a2 + * 20(sp) - d0 + * 24(sp) - orig_d0 + * 28(sp) - stack adjustment + * 2C(sp) - sr + * 2E(sp) - pc + * 32(sp) - format & vector */ /* @@ -47,6 +48,11 @@ * number 0 in the 'current_set' list. */ +/* + * 97/05/14 Andreas: Register %a2 is now set to the current task throughout + * the whole kernel. + */ + #include <linux/sys.h> #include <linux/config.h> #include <linux/linkage.h> @@ -57,6 +63,8 @@ .globl SYMBOL_NAME(kgdb_registers) #endif +#define curptr a2 + LENOSYS = 38 /* @@ -80,15 +88,15 @@ LTASK_FLAGS = 20 #define MAX_NOINT_IPL 0 #endif /* machine compilation types */ -LD0 = 0x1C -LORIG_D0 = 0x20 -LSR = 0x28 -LFORMATVEC = 0x2E +LD0 = 0x20 +LORIG_D0 = 0x24 +LSR = 0x2C +LFORMATVEC = 0x32 /* * This defines the normal kernel pt-regs layout. * - * regs are a2-a6 and d6-d7 preserved by C code + * regs a3-a6 and d6-d7 are preserved by C code * the kernel doesn't mess with usp unless it needs to */ #ifndef CONFIG_KGDB @@ -96,7 +104,7 @@ LFORMATVEC = 0x2E clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1,%sp@- + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; #else /* Need to save the "missing" registers for kgdb... */ @@ -104,25 +112,30 @@ LFORMATVEC = 0x2E clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1,%sp@-; \ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \ moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \ - moveml %a2-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A2 + moveml %a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3; #endif #define RESTORE_ALL \ - moveml %sp@+,%a0-%a1/%d1-%d5; \ + moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \ movel %sp@+,%d0; \ addql #4,%sp; /* orig d0 */ \ addl %sp@+,%sp; /* stk adj */ \ rte -#define SWITCH_STACK_SIZE (7*4+4) /* includes return address */ +#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ #define SAVE_SWITCH_STACK \ - moveml %a2-%a6/%d6-%d7,%sp@- + moveml %a3-%a6/%d6-%d7,%sp@- #define RESTORE_SWITCH_STACK \ - moveml %sp@+,%a2-%a6/%d6-%d7 + moveml %sp@+,%a3-%a6/%d6-%d7 + +#define GET_CURRENT(tmp) \ + movel %sp,tmp; \ + andw &-8192,tmp; \ + movel tmp,%curptr; .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) @@ -139,6 +152,7 @@ ENTRY(buserr) | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(buserr_c) addql #4,%sp @@ -150,6 +164,7 @@ ENTRY(trap) movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) addql #4,%sp @@ -190,6 +205,7 @@ ENTRY(system_call) SAVE_ALL movel %d0,%d2 + GET_CURRENT(%d0) | save top of frame pea %sp@ jbsr SYMBOL_NAME(set_esp0) @@ -197,8 +213,7 @@ ENTRY(system_call) cmpl #NR_syscalls,%d2 jcc badsys - movel SYMBOL_NAME(current_set),%a0 - btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS + btst #5,%curptr@(LTASK_FLAGS+3) | PF_TRACESYS jne do_trace jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) movel %d0,%sp@(LD0) | save the return value @@ -208,24 +223,23 @@ SYMBOL_NAME_LABEL(ret_from_exception) bnes 2f | if so, skip resched, signals tstl SYMBOL_NAME(need_resched) jne SYMBOL_NAME(reschedule) - movel SYMBOL_NAME(current_set),%a0 - cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals + cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals jeq 2f - bclr #5,%a0@(LTASK_FLAGS+1) | check for delayed trace + bclr #5,%curptr@(LTASK_FLAGS+1) | check for delayed trace jne do_delayed_trace 5: - tstl %a0@(LTASK_STATE) | state + tstl %curptr@(LTASK_STATE) | state jne SYMBOL_NAME(reschedule) - tstl %a0@(LTASK_COUNTER) | counter + tstl %curptr@(LTASK_COUNTER) | counter jeq SYMBOL_NAME(reschedule) - movel %a0@(LTASK_BLOCKED),%d0 + movel %curptr@(LTASK_BLOCKED),%d0 movel %d0,%d1 | save blocked in d1 for sig handling notl %d0 - btst #4,%a0@(LTASK_FLAGS+3) | PF_PTRACED + btst #4,%curptr@(LTASK_FLAGS+3) | PF_PTRACED jeq 1f moveq #-1,%d0 | let the debugger see all signals -1: andl %a0@(LTASK_SIGNAL),%d0 +1: andl %curptr@(LTASK_SIGNAL),%d0 jne Lsignal_return 2: RESTORE_ALL @@ -248,7 +262,6 @@ do_delayed_trace: jbsr SYMBOL_NAME(send_sig) addql #8,%sp addql #4,%sp - movel SYMBOL_NAME(current_set),%a0 jra 5b /* @@ -260,6 +273,7 @@ SYMBOL_NAME_LABEL(inthandler) movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall + GET_CURRENT(%d0) addql #1,SYMBOL_NAME(local_irq_count) | put exception # in d0 bfextu %sp@(LFORMATVEC){#4,#10},%d0 @@ -270,28 +284,31 @@ SYMBOL_NAME_LABEL(inthandler) addql #8,%sp | pop parameters off stack SYMBOL_NAME_LABEL(ret_from_interrupt) - /* check if we need to do software interrupts */ - movel SYMBOL_NAME(local_irq_count),%d1 - subql #1,%d1 - jne 4f -#if 0 - bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt. + subql #1,SYMBOL_NAME(local_irq_count) + jeq 1f +2: + RESTORE_ALL +1: +#if 1 + bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt. #if MAX_NOINT_IPL > 0 cmpiw #MAX_NOINT_IPL,%d0 #endif - jhi 4f + jhi 2b #endif + /* Let the rest run with interrupts allowed. This is safe since + the kernel never uses a non-standard ipl and this is the outer + level interrupt. */ + andw #ALLOWINT,%sr + + /* check if we need to do software interrupts */ + movel SYMBOL_NAME(bh_active),%d0 andl SYMBOL_NAME(bh_mask),%d0 - jeq 3f + jeq SYMBOL_NAME(ret_from_exception) - jbsr SYMBOL_NAME(do_bottom_half) -3: - clrl SYMBOL_NAME(local_irq_count) - jra SYMBOL_NAME(ret_from_exception) -4: - movel %d1,SYMBOL_NAME(local_irq_count) - RESTORE_ALL + pea SYMBOL_NAME(ret_from_exception) + jra SYMBOL_NAME(do_bottom_half) /* Handler for uninitialized and spurious interrupts */ @@ -398,7 +415,7 @@ SYMBOL_NAME_LABEL(resume) 3: /* get pointer to tss struct (a1 contains new task) */ - movel %a1,SYMBOL_NAME(current_set) + movel %a1,%curptr addl %d1,%a1 /* Skip address space switching if they are the same. */ @@ -419,7 +436,7 @@ SYMBOL_NAME_LABEL(resume) movec %cacr,%d0 oriw #LFLUSH_I_AND_D,%d0 movec %d0,%cacr - + /* switch the root pointer */ pmove %a1@(LTSS_CRP),%crp #endif diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index c2b72aa2d..36a4072ac 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -223,17 +223,9 @@ ENTRY(_start) movel %d0,%a0@ /* save cache mode for page tables */ /* - * raise interrupt level with MASTER bit set, copy isp to msp (if not 68060) + * raise interrupt level */ -#ifdef FROM_PL9 - movew #0x3700,%sr - is_060(1f) - movec %isp,%d0 - movel %d0,%sp -1: -#else movew #0x2700,%sr -#endif /* If running on an Atari, determine the I/O base of the @@ -896,8 +888,10 @@ Lcache68060: /* * Setup initial stack pointer + * We need to get current loaded up with our first task... */ - lea SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp + lea SYMBOL_NAME(init_task_union),%a2 + lea 8192(%a2),%sp /* jump to the kernel start */ putr() diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index f49c38cd3..39e1fbce6 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -29,6 +29,7 @@ #include <linux/sched.h> #include <linux/kernel_stat.h> #include <linux/errno.h> +#include <linux/init.h> #include <asm/system.h> #include <asm/irq.h> @@ -79,7 +80,7 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; * the IRQ handling routines. */ -void init_IRQ(void) +__initfunc(void init_IRQ(void)) { int i; diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 3138d99df..f6bb0689b 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -6,6 +6,8 @@ #include <linux/mm.h> #include <linux/user.h> #include <linux/elfcore.h> +#include <linux/in6.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/machdep.h> @@ -14,6 +16,7 @@ #include <asm/semaphore.h> #include <asm/checksum.h> #include <asm/hardirq.h> +#include <asm/softirq.h> asmlinkage long long __ashrdi3 (long long, int); extern char m68k_debug_device[]; @@ -40,6 +43,7 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(__m68k_bh_counter); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 5422831a8..ad0662f22 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -10,6 +10,7 @@ * This file handles the architecture-dependent parts of process handling.. */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -29,6 +30,23 @@ #include <asm/traps.h> #include <asm/machdep.h> #include <asm/setup.h> +#include <asm/pgtable.h> + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +union task_union init_task_union + __attribute__((section("init_task"), aligned(2*PAGE_SIZE))) + = { task: INIT_TASK }; asmlinkage void ret_from_exception(void); @@ -46,8 +64,17 @@ asmlinkage int sys_idle(void) /* endless idle loop with no priority at all */ current->priority = -100; current->counter = -100; - for (;;) + for (;;){ + if (!need_resched) +#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) + /* block out HSYNC on the atari (falcon) */ + __asm__("stop #0x2200" : : : "cc"); +#else /* portable version */ + __asm__("stop #0x2000" : : : "cc"); +#endif /* machine compilation types */ + run_task_queue(&tq_scheduler); schedule(); + } ret = 0; out: unlock_kernel(); @@ -76,8 +103,8 @@ void show_regs(struct pt_regs * regs) printk("\n"); printk("Format %02x Vector: %04x PC: %08lx Status: %04x\n", regs->format, regs->vector, regs->pc, regs->sr); - printk("ORIG_D0: %08lx D0: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a1); + printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); printk("A0: %08lx D5: %08lx D4: %08lx\n", regs->a0, regs->d5, regs->d4); printk("D3: %08lx D2: %08lx D1: %08lx\n", @@ -144,8 +171,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct switch_stack * childstack, *stack; unsigned long stack_offset, *retp; - stack_offset = PAGE_SIZE - sizeof(struct pt_regs); - childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset); + stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs); + childregs = (struct pt_regs *) ((unsigned long) p + stack_offset); *childregs = *regs; childregs->d0 = 0; @@ -231,7 +258,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->regs.d7 = sw->d7; dump->regs.a0 = regs->a0; dump->regs.a1 = regs->a1; - dump->regs.a2 = sw->a2; + dump->regs.a2 = regs->a2; dump->regs.a3 = sw->a3; dump->regs.a4 = sw->a4; dump->regs.a5 = sw->a5; diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 70e341b31..be4149cbb 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -47,23 +47,11 @@ static int regoff[] = { PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), - PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4), + PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4), SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), }; -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -116,7 +104,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -126,7 +114,7 @@ repeat: } pgmiddle = pmd_offset(pgdir,addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -137,7 +125,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -168,7 +156,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -178,7 +166,7 @@ repeat: } pgmiddle = pmd_offset(pgdir,addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -189,12 +177,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 2); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -340,7 +328,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index dfd91d0d4..def50a747 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -18,6 +18,7 @@ #include <linux/genhd.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/init.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -55,13 +56,13 @@ static struct mem_info m68k_ramdisk = { 0, 0 }; static char m68k_command_line[CL_SIZE]; char saved_command_line[CL_SIZE]; -void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)); +void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ -int (*mach_keyb_init) (void); +int (*mach_keyb_init) (void) __initdata; int (*mach_kbdrate) (struct kbd_repeat *) = NULL; void (*mach_kbd_leds) (unsigned int) = NULL; /* machine dependent irq functions */ -void (*mach_init_IRQ) (void); +void (*mach_init_IRQ) (void) __initdata; void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; void (*mach_get_model) (char *model) = NULL; int (*mach_get_hardware_list) (char *buffer) = NULL; @@ -73,12 +74,12 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*); int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); -struct fb_info *(*mach_fb_init)(long *); +struct fb_info *(*mach_fb_init)(long *) __initdata; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -void (*mach_video_setup) (char *, int *); +void (*mach_video_setup) (char *, int *) __initdata; #ifdef CONFIG_BLK_DEV_FD -int (*mach_floppy_init) (void) = NULL; -void (*mach_floppy_setup) (char *, int *) = NULL; +int (*mach_floppy_init) (void) __initdata = NULL; +void (*mach_floppy_setup) (char *, int *) __initdata = NULL; void (*mach_floppy_eject) (void) = NULL; #endif @@ -94,7 +95,7 @@ extern void config_apollo(void); #define MASK_256K 0xfffc0000 -static void m68k_parse_bootinfo(const struct bi_record *record) +__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) { while (record->tag != BI_LAST) { int unknown = 0; @@ -141,8 +142,8 @@ static void m68k_parse_bootinfo(const struct bi_record *record) } } -void setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p) + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p)) { unsigned long memory_start, memory_end; extern int _etext, _edata, _end; @@ -337,7 +338,7 @@ int get_hardware_list(char *buffer) } #ifdef CONFIG_BLK_DEV_FD -int floppy_init(void) +__initfunc(int floppy_init(void)) { if (mach_floppy_init) return mach_floppy_init(); @@ -345,7 +346,7 @@ int floppy_init(void) return 0; } -void floppy_setup(char *str, int *ints) +__initfunc(void floppy_setup(char *str, int *ints)) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -358,7 +359,7 @@ void floppy_eject(void) } #endif -unsigned long arch_kbd_init(void) +__initfunc(unsigned long arch_kbd_init(void)) { return mach_keyb_init(); } @@ -372,7 +373,7 @@ void arch_gettod(int *year, int *mon, int *day, int *hour, *year = *mon = *day = *hour = *min = *sec = 0; } -void video_setup (char *options, int *ints) +__initfunc(void video_setup (char *options, int *ints)) { if (mach_video_setup) mach_video_setup (options, ints); diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index c60e82b0b..52c13445d 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -42,7 +42,9 @@ #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); + asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); const int frame_extra_sizes[16] = { @@ -466,7 +468,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs) if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) /* nothing */; continue; } diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 5acfd1cbd..e29509cac 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -532,12 +532,15 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) */ vma = find_vma (current->mm, addr); ret = -EINVAL; + /* Check for overflow. */ + if (addr + len < addr) + goto out; if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) goto out; } if (CPU_IS_020_OR_030) { - if (scope == FLUSH_SCOPE_LINE) { + if (scope == FLUSH_SCOPE_LINE && len < 256) { unsigned long cacr; __asm__ ("movec %%cacr, %0" : "=r" (cacr)); if (cache & FLUSH_CACHE_INSN) diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index dbff49276..7b3acdfa6 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -27,6 +27,24 @@ static inline int set_rtc_mmss(unsigned long nowtime) return -1; } +static inline void do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + if (pc < prof_len) + ++prof_buffer[pc]; + else + /* + * Dont ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + ++prof_buffer[prof_len-1]; + } +} + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -38,6 +56,9 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) do_timer(regs); + if (!user_mode(regs)) + do_profile(regs->pc); + /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 1cc547907..25be40007 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -27,6 +27,7 @@ #include <linux/user.h> #include <linux/string.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/setup.h> #include <asm/fpu.h> @@ -63,7 +64,7 @@ asm(".text\n" __ALIGN_STR "\n" SYMBOL_NAME_STR(nmihandler) ": rte"); -void trap_init (void) +__initfunc(void trap_init (void)) { int i; @@ -932,16 +933,15 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr) #endif console_verbose(); printk("%s: %08x\n",str,nr); - printk("PC: [<%08lx>]\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); + printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", + fp->pc, fp->sr, fp, fp->a2); printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", fp->d0, fp->d1, fp->d2, fp->d3); printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) - printk("Corrupted stack page\n"); printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, current->kernel_stack_page); + current->comm, current->pid, PAGE_SIZE+(unsigned long)current); #ifdef CONFIG_KGDB } #endif diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S index 76ffc3cc5..8e4141149 100644 --- a/arch/m68k/lib/semaphore.S +++ b/arch/m68k/lib/semaphore.S @@ -19,8 +19,7 @@ ENTRY(__down_failed) movel %a1,-(%sp) jbsr SYMBOL_NAME(__down) movel (%sp)+,%a1 - movel (%sp)+,%d0 - movel (%sp)+,%d1 + moveml (%sp)+,%a0/%d0/%d1 rts ENTRY(__down_failed_interruptible) @@ -30,6 +29,7 @@ ENTRY(__down_failed_interruptible) jbsr SYMBOL_NAME(__down_interruptible) movel (%sp)+,%a1 movel (%sp)+,%d1 + movel (%sp)+,%a0 rts ENTRY(__up_wakeup) @@ -37,6 +37,5 @@ ENTRY(__up_wakeup) movel %a1,-(%sp) jbsr SYMBOL_NAME(__up) movel (%sp)+,%a1 - movel (%sp)+,%d0 - movel (%sp)+,%d1 + moveml (%sp)+,%a0/%d0/%d1 rts diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 71b46e2d9..193c6baee 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -32,14 +32,10 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { - void (*handler)(struct task_struct *, - struct vm_area_struct *, - unsigned long, - int); struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; struct vm_area_struct * vma; - unsigned long fixup, fault_pc; + unsigned long fixup; int write; #ifdef DEBUG @@ -73,10 +69,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, */ good_area: write = 0; - handler = do_no_page; switch (error_code & 3) { default: /* 3: write, present */ - handler = do_wp_page; /* fall through */ case 2: /* write, not present */ if (!(vma->vm_flags & VM_WRITE)) @@ -89,7 +83,7 @@ good_area: if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handler(tsk, vma, address, write); + handle_mm_fault(current, vma, address, write); up(&mm->mmap_sem); /* There seems to be a missing invalidate somewhere in do_no_page. @@ -108,10 +102,10 @@ bad_area: up(&mm->mmap_sem); /* Are we prepared to handle this fault? */ - fault_pc = regs->pc; - if ((fixup = search_exception_table(fault_pc)) != 0) { + if ((fixup = search_exception_table(regs->pc)) != 0) { struct pt_regs *tregs; - printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", fault_pc, fixup); + printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", + current->comm, regs->pc, fixup); /* Create a new four word stack frame, discarding the old one. */ regs->stkadj = frame_extra_sizes[regs->format]; diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 01cd315dd..b46037f80 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/types.h> +#include <linux/init.h> #ifdef CONFIG_BLK_DEV_RAM #include <linux/blk.h> #endif @@ -116,9 +117,8 @@ pte_t *kernel_page_table (unsigned long *memavailp) return ptablep; } -static unsigned long map_chunk (unsigned long addr, - unsigned long size, - unsigned long *memavailp) +__initfunc(static unsigned long +map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp)) { #define ONEMEG (1024*1024) #define L3TREESIZE (256*1024) @@ -283,6 +283,11 @@ static unsigned long map_chunk (unsigned long addr, extern unsigned long free_area_init(unsigned long, unsigned long); +/* References to section boundaries */ + +extern char _text, _etext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* @@ -291,7 +296,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; * The parameters are pointers to where to stick the starting and ending * addresses of available kernel virtual memory. */ -unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { int chunk; unsigned long mem_avail = 0; @@ -395,12 +400,12 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) return PAGE_ALIGN(free_area_init (start_mem, end_mem)); } -void mem_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { int codepages = 0; int datapages = 0; + int initpages = 0; unsigned long tmp; - extern int _etext; end_mem &= PAGE_MASK; high_memory = (void *) end_mem; @@ -448,8 +453,15 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) if (VTOP (tmp) >= mach_max_dma_address) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp < (unsigned long)&_etext) - codepages++; + if (tmp >= (unsigned long)&_text + && tmp < (unsigned long)&_edata) { + if (tmp < (unsigned long) &_etext) + codepages++; + else + datapages++; + } else if (tmp >= (unsigned long) &__init_begin + && tmp < (unsigned long) &__init_end) + initpages++; else datapages++; continue; @@ -461,16 +473,24 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) #endif free_page(tmp); } - printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", + printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10)); + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); } void free_initmem(void) { - /* To be written */ + unsigned long addr; + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + atomic_set(&mem_map[MAP_NR(addr)].count, 1); + free_page(addr); + } } void si_meminfo(struct sysinfo *val) diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 55d5e98f3..77eb2dbfe 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -280,6 +280,8 @@ static unsigned long transp_transl_matches( unsigned long regval, return( (vaddr & mask) == (base & mask) ); } +static unsigned long mm_vtop_fallback (unsigned long); + /* * The following two routines map from a physical address to a kernel * virtual address and vice versa. @@ -301,7 +303,13 @@ unsigned long mm_vtop (unsigned long vaddr) offset += m68k_memory[i].size; i++; }while (i < m68k_num_memory); + return mm_vtop_fallback(vaddr); +} +/* Separate function to make the common case faster (needs to save less + registers) */ +static unsigned long mm_vtop_fallback (unsigned long vaddr) +{ /* not in one of the memory chunks; test for applying transparent * translation */ diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds new file mode 100644 index 000000000..cc5b1e20e --- /dev/null +++ b/arch/m68k/vmlinux.lds @@ -0,0 +1,60 @@ +/* ld script to make m68k Linux kernel */ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_start) +SECTIONS +{ + . = 0x1000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.text.lock) /* out-of-line lock text */ + *(.gnu.warning) + } = 0x4e75 + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + . = ALIGN(8192); + init_task : { *(init_task) } /* The initial task and kernel stack */ + + _edata = .; /* End of data section */ + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 5ea699450..1aa371ae1 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -156,9 +156,9 @@ endif # The pipe options is bad for my low-mem machine # Uncomment this if you want this. # -#CFLAGS += -pipe +CFLAGS += -pipe -HEAD := arch/mips/kernel/head.o +HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools) CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES) diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index fd445c865..dd834efd9 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -34,7 +34,11 @@ mkboot: mkboot.c $(HOSTCC) -o $@ $^ zdisk: zImage - mcopy -o zImage a:vmlinux + if [ -f /etc/remote-mcopy ]; then \ + ssh rio mcopy -o - a:vmlinux <zImage; \ + else \ + mcopy -o zImage a:vmlinux; \ + fi dep: $(CPP) -M *.[cS] > .depend diff --git a/arch/mips/boot/mkboot.c b/arch/mips/boot/mkboot.c index 48f27113e..35612d248 100644 --- a/arch/mips/boot/mkboot.c +++ b/arch/mips/boot/mkboot.c @@ -355,7 +355,7 @@ main(argc, argv) char *infile, *outfile; struct stat ifstat; off_t ifsize; - void *image; + char *image; int ifd, ofd, i, symtabix, strtabix; Elf32_Ehdr eh; Elf32_Phdr *ph; @@ -421,7 +421,7 @@ main(argc, argv) * we're reading might have different type sizes, byteorder * or alignment than the host. */ - memcpy(eh.e_ident, image, sizeof(eh.e_ident)); + memcpy(eh.e_ident, (void *)image, sizeof(eh.e_ident)); if(memcmp(eh.e_ident, ELFMAG, SELFMAG)) { fprintf(stderr, "Input file isn't a ELF file\n"); exit(1); @@ -476,7 +476,7 @@ main(argc, argv) exit(1); } for(i = 0;i < eh.e_phnum; i++) - get_elfph(image + eh.e_phoff + i * 32, ph + i); + get_elfph((void *)(image + eh.e_phoff + i * 32), ph + i); /* * ... and then the section headers. @@ -487,7 +487,7 @@ main(argc, argv) exit(1); } for(i = 0;i < eh.e_shnum; i++) - get_elfsh(image + eh.e_shoff + (i * 40), sh + i); + get_elfsh((void *)(image + eh.e_shoff + (i * 40)), sh + i); /* * Find the symboltable and the stringtable in the file. diff --git a/arch/mips/config.in b/arch/mips/config.in index a0e655ea1..14e9dec3f 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -178,23 +178,27 @@ fi source fs/Config.in if [ "$CONFIG_SGI" != "y" ]; then - source drivers/char/Config.in + source drivers/char/Config.in - mainmenu_option next_comment - comment 'Sound' + mainmenu_option next_comment + comment 'Sound' - tristate 'Sound card support' CONFIG_SOUND - if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in - fi - endmenu + tristate 'Sound card support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in + fi + endmenu else - comment 'SGI Character Devices' - tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE - bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL - if [ "$CONFIG_SGI_SERIAL" != "n" ]; then - define_bool CONFIG_SERIAL y - fi + comment 'SGI Character Devices' + bool 'Virtual terminal' CONFIG_VT + if [ "$CONFIG_VT" = "y" ]; then + bool 'Console on virtual terminal' CONFIG_VT_CONSOLE + fi + tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE + bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL + if [ "$CONFIG_SGI_SERIAL" != "n" ]; then + define_bool CONFIG_SERIAL y + fi fi mainmenu_option next_comment diff --git a/arch/mips/defconfig b/arch/mips/defconfig index dc28a8cd8..33f54a301 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -22,6 +22,7 @@ CONFIG_PCI=y # # CONFIG_CPU_R3000 is not set # CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R4300 is not set CONFIG_CPU_R4X00=y # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R8000 is not set diff --git a/arch/mips/deskstation/io.c b/arch/mips/deskstation/io.c new file mode 100644 index 000000000..cd33e2eb6 --- /dev/null +++ b/arch/mips/deskstation/io.c @@ -0,0 +1,68 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Low level I/O functions for Jazz family machine. + * + * FIXME: This implementation fits the Tyne. How does the EISA rPC44 handle + * the eight high address bits? + */ +#include <linux/string.h> +#include <asm/mipsconfig.h> +#include <asm/addrspace.h> +#include <asm/sni.h> + +/* + * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped + * for the processor. + */ +extern unsigned long isa_slot_offset; + +static unsigned char deskstation_readb(unsigned long addr) +{ + return *(volatile unsigned char *) (isa_slot_offset + addr); +} + +static unsigned short deskstation_readw(unsigned long addr) +{ + return *(volatile unsigned short *) (isa_slot_offset + addr); +} + +static unsigned int deskstation_readl(unsigned long addr) +{ + return *(volatile unsigned int *) (isa_slot_offset + addr); +} + +static void deskstation_writeb(unsigned char val, unsigned long addr) +{ + *(volatile unsigned char *) (isa_slot_offset + addr) = val; +} + +static void deskstation_writew(unsigned short val, unsigned long addr) +{ + *(volatile unsigned char *) (isa_slot_offset + addr) = val; +} + +static void deskstation_writel(unsigned int val, unsigned long addr) +{ + *(volatile unsigned char *) (isa_slot_offset + addr) = val; +} + +static void deskstation_memset_io(unsigned long addr, int val, unsigned long len) +{ + addr += isa_slot_offset; + memset((void *)addr, val, len); +} + +static void deskstation_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len) +{ + from += isa_slot_offset; + memcpy((void *)to, (void *)from, len); +} + +static void deskstation_memcpy_toio(unsigned long to, unsigned long from, unsigned long len) +{ + to += isa_slot_offset; + memcpy((void *)to, (void *)from, len); +} diff --git a/arch/mips/deskstation/setup.c b/arch/mips/deskstation/setup.c index c2451e855..8b70a656c 100644 --- a/arch/mips/deskstation/setup.c +++ b/arch/mips/deskstation/setup.c @@ -5,10 +5,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 1997 by Ralf Baechle */ -#include <asm/ptrace.h> #include <linux/config.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/interrupt.h> @@ -16,6 +16,7 @@ #include <asm/bootinfo.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/ptrace.h> #include <asm/mipsregs.h> #include <asm/reboot.h> #include <asm/vector.h> @@ -43,8 +44,7 @@ extern void deskstation_machine_power_off(void); unsigned long mips_dma_cache_size = 0; unsigned long mips_dma_cache_base = KSEG0; -static void -tyne_irq_setup(void) +__initfunc(static void tyne_irq_setup(void)) { set_except_vector(0, deskstation_handle_int); /* set the clock to 100 Hz */ @@ -58,8 +58,7 @@ tyne_irq_setup(void) #endif #ifdef CONFIG_DESKSTATION_RPC44 -static void -rpc44_irq_setup(void) +__initfunc(static void rpc44_irq_setup(void)) { /* * For the moment just steal the TYNE support. In the @@ -77,8 +76,7 @@ rpc44_irq_setup(void) } #endif -void -deskstation_setup(void) +__initfunc(void deskstation_setup(void)) { switch(mips_machtype) { #ifdef CONFIG_DESKSTATION_TYNE diff --git a/arch/mips/jazz/.cvsignore b/arch/mips/jazz/.cvsignore new file mode 100644 index 000000000..4671378ae --- /dev/null +++ b/arch/mips/jazz/.cvsignore @@ -0,0 +1 @@ +.depend diff --git a/arch/mips/jazz/io.c b/arch/mips/jazz/io.c new file mode 100644 index 000000000..a151b99fe --- /dev/null +++ b/arch/mips/jazz/io.c @@ -0,0 +1,136 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Low level I/O functions for Jazz family machines. + * + * Copyright (C) 1997 by Ralf Baechle. + */ +#include <linux/string.h> +#include <asm/mipsconfig.h> +#include <asm/addrspace.h> +#include <asm/system.h> +#include <asm/spinlock.h> +#include <asm/jazz.h> + +/* + * Map an 16mb segment of the EISA address space to 0xe3000000; + */ +static inline void map_eisa_address(unsigned long address) +{ + /* XXX */ + /* We've got an wired entry in the TLB. We just need to modify it. + fast and clean. But since we want to get rid of wired entries + things are a little bit more complicated ... */ +} + +static unsigned char jazz_readb(unsigned long addr) +{ + unsigned char res; + + map_eisa_address(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr); + + return res; +} + +static unsigned short jazz_readw(unsigned long addr) +{ + unsigned short res; + + map_eisa_address(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr); + + return res; +} + +static unsigned int jazz_readl(unsigned long addr) +{ + unsigned int res; + + map_eisa_address(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (JAZZ_EISA_BASE + addr); + + return res; +} + +static void jazz_writeb(unsigned char val, unsigned long addr) +{ + map_eisa_address(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val; +} + +static void jazz_writew(unsigned short val, unsigned long addr) +{ + map_eisa_address(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val; +} + +static void jazz_writel(unsigned int val, unsigned long addr) +{ + map_eisa_address(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (JAZZ_EISA_BASE + addr) = val; +} + +static void jazz_memset_io(unsigned long addr, int val, unsigned long len) +{ + unsigned long waddr; + + waddr = JAZZ_EISA_BASE | (addr & 0xffffff); + while(len) { + unsigned long fraglen; + + fraglen = (~addr + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + map_eisa_address(addr); + memset((char *)waddr, val, fraglen); + addr += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } +} + +static void jazz_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len) +{ + unsigned long waddr; + + waddr = JAZZ_EISA_BASE | (from & 0xffffff); + while(len) { + unsigned long fraglen; + + fraglen = (~from + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + map_eisa_address(from); + memcpy((void *)to, (void *)waddr, fraglen); + to += fraglen; + from += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } +} + +static void jazz_memcpy_toio(unsigned long to, unsigned long from, unsigned long len) +{ + unsigned long waddr; + + waddr = JAZZ_EISA_BASE | (to & 0xffffff); + while(len) { + unsigned long fraglen; + + fraglen = (~to + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + map_eisa_address(to); + memcpy((char *)to + JAZZ_EISA_BASE, (void *)from, fraglen); + to += fraglen; + from += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } +} diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 1b137cf85..805efa821 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -5,14 +5,15 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 1997 by Ralf Baechle */ -#include <asm/ptrace.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <asm/irq.h> #include <asm/jazz.h> +#include <asm/ptrace.h> #include <asm/reboot.h> #include <asm/vector.h> #include <asm/io.h> @@ -35,8 +36,7 @@ extern void jazz_machine_restart(char *command); extern void jazz_machine_halt(void); extern void jazz_machine_power_off(void); -static void -jazz_irq_setup(void) +__initfunc(static void jazz_irq_setup(void)) { set_except_vector(0, jazz_handle_int); r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, @@ -55,8 +55,7 @@ jazz_irq_setup(void) setup_x86_irq(2, &irq2); } -void -jazz_setup(void) +__initfunc(void jazz_setup(void)) { irq_setup = jazz_irq_setup; fd_cacheflush = jazz_fd_cacheflush; diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index b251d6e1a..21dd3610b 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -9,7 +9,7 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -all: kernel.o head.o +all: kernel.o head.o init_task.o EXTRA_ASFLAGS = -mips3 -mcpu=r4000 O_TARGET := kernel.o O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \ diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 8bb8fb41c..682e00cda 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -14,9 +14,11 @@ * and faults that can result in a task-switch. The ISA dependent TLB * code is in arch/mips/<ISA-level>/<cputype>.S */ +#include <linux/config.h> #include <linux/sys.h> #include <asm/asm.h> +#include <asm/current.h> #include <asm/errno.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> @@ -53,7 +55,6 @@ reschedule: nop EXPORT(ret_from_sys_call) - lw t0,bh_mask lw t1,bh_active # unused delay slot and t0,t1 @@ -64,7 +65,7 @@ EXPORT(ret_from_sys_call) beqz t1,return # -> yes lw t1,need_resched bnez t1,reschedule - lw s0,current_set + GET_CURRENT(s0) lw t0,task lw a0,TASK_BLOCKED(s0) diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index a957e16bd..4c3e5bd52 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -22,6 +22,15 @@ #include <asm/bootinfo.h> #include <asm/cpu.h> +/* + * Get current task pointer + */ +#define GET_CURRENT(reg) \ + lui reg, %hi(kernelsp); \ + lw reg, %lo(kernelsp)(reg); \ + ori reg, 8191; \ + xori reg, 8191 + .text /* * Reserved space for exception handlers. @@ -43,8 +52,7 @@ LEAF(except_vec0_r4000) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) # get current task ptr + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 # get pgd only bits lw k1, THREAD_PGDIR(k1) # get task pg_dir sll k0, k0, 2 @@ -71,8 +79,7 @@ LEAF(except_vec0_r4600) .set mips3 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -98,8 +105,7 @@ LEAF(except_vec0_r45k_bvahwbug) .set mips3 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -129,8 +135,7 @@ LEAF(except_vec0_r4k_mphwbug) .set mips3 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -160,8 +165,7 @@ LEAF(except_vec0_r4k_250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -191,8 +195,7 @@ LEAF(except_vec0_r4k_MP250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -224,8 +227,7 @@ LEAF(except_vec0_r2300) .set mips1 mfc0 k0, CP0_BADVADDR - lui k1, %hi(current_set) - lw k1, %lo(current_set)(k1) + GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 @@ -403,9 +405,11 @@ probe_done: /* * Stack for kernel and init + * + * Kernelsp will never be referenced for process 0. */ -9: la sp, init_user_stack+(KERNEL_STACK_SIZE-4*SZREG) - la t0, init_kernel_stack+(KERNEL_STACK_SIZE) +9: la sp, init_task_union+(KERNEL_STACK_SIZE-4*SZREG) + la t0, init_task_union+(KERNEL_STACK_SIZE) sw t0, kernelsp /* Disable coprocessors */ @@ -745,9 +749,13 @@ map0_sni_rm200_pci: .org 0x6000 + /* + * init_task_union follows here in the .text segment. + * Keep this aligned to a 8kb boundary! + */ + .data EXPORT(cache_error_buffer) .fill 32*4,1,0 - .data EXPORT(kernelsp) PTR 0 diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c new file mode 100644 index 000000000..cc0a19231 --- /dev/null +++ b/arch/mips/kernel/init_task.c @@ -0,0 +1,22 @@ +#include <linux/mm.h> +#include <linux/sched.h> + +#include <asm/pgtable.h> + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance.. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff --git a/arch/mips/kernel/irix5sys.h b/arch/mips/kernel/irix5sys.h index a20e619e3..be57dc1f5 100644 --- a/arch/mips/kernel/irix5sys.h +++ b/arch/mips/kernel/irix5sys.h @@ -105,7 +105,7 @@ SYS(irix_sgikopt, 3) /* 1083 sys_sgikopt() DC*/ SYS(sys_sysfs, 3) /* 1084 sysfs() ?V*/ SYS(irix_unimp, 0) /* 1085 XXX sys_getmsg() DC*/ SYS(irix_unimp, 0) /* 1086 XXX sys_putmsg() DC*/ -SYS(irix_poll, 3) /* 1087 sys_poll() V*/ +SYS(sys_poll, 3) /* 1087 poll() V*/ SYS(irix_sigreturn, 0) /* 1088 sigreturn() ?V*/ SYS(sys_accept, 3) /* 1089 accept() V*/ SYS(sys_bind, 3) /* 1090 bind() V*/ diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 46345b308..d994155d0 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -1,4 +1,4 @@ -/* $Id: irixelf.c,v 1.8 1996/08/24 03:52:25 dm Exp $ +/* * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. * @@ -17,6 +17,7 @@ #include <linux/mman.h> #include <linux/a.out.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/signal.h> #include <linux/binfmts.h> #include <linux/string.h> @@ -720,16 +721,16 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm, sys_close(elf_exec_fileno); current->personality = PER_IRIX32; - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); current->exec_domain = lookup_exec_domain(current->personality); current->binfmt = &irix_format; - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)++; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)++; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_INC_USE_COUNT(current->binfmt->module); current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; @@ -1180,20 +1181,20 @@ static int irix_core_dump(long signr, struct pt_regs * regs) notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; - copy_sigbits32(&prstatus.pr_sigpend, current->signal); - copy_sigbits32(&prstatus.pr_sighold, current->blocked); + prstatus.pr_sigpend = current->signal; + prstatus.pr_sighold = current->blocked; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; psinfo.pr_sid = prstatus.pr_sid = current->session; - prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime); - prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime); - prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime); - prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime); - prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime); - prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime); - prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime); - prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime); + prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); + prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); + prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); + prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); + prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); + prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); + prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); + prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) " "(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs)); @@ -1339,13 +1340,15 @@ static int irix_core_dump(long signr, struct pt_regs * regs) return has_dumped; } -int init_irix_binfmt(void) { +__initfunc(int init_irix_binfmt(void)) +{ return register_binfmt(&irix_format); } #ifdef MODULE -int init_module(void) { +int init_module(void) +{ /* Install the COFF, ELF and XOUT loaders. * N.B. We *rely* on the table being the right size with the * right number of free slots... @@ -1354,7 +1357,8 @@ int init_module(void) { } -void cleanup_module( void) { +void cleanup_module( void) +{ /* Remove the IRIX ELF loaders. */ unregister_binfmt(&irix_format); } diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c index 3405904fa..e0230f9f0 100644 --- a/arch/mips/kernel/irixioctl.c +++ b/arch/mips/kernel/irixioctl.c @@ -8,6 +8,8 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/tty.h> #include <asm/uaccess.h> diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 6a5636c76..b2d7cbe49 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -8,6 +8,8 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/time.h> #include <asm/ptrace.h> @@ -162,7 +164,10 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; @@ -175,15 +180,19 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: + lock_kernel(); if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; } + unlock_kernel(); /* fall through */ default: current->signal |= _S(signr & 0x7f); current->flags |= PF_SIGNALED; + lock_kernel(); /* 8-( */ do_exit(signr); + unlock_kernel(); } } /* @@ -314,7 +323,7 @@ static inline void check_pending(int signum) spin_lock(¤t->sigmask_lock); if (p->sa_handler == SIG_IGN) { current->signal &= ~_S(signum); - } else if if (p->sa_handler == SIG_DFL) { + } else if (p->sa_handler == SIG_DFL) { if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH) return; current->signal &= ~_S(signum); @@ -347,11 +356,9 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, if(sig == SIGKILL || sig == SIGSTOP) { return -EINVAL; } - new_sa.sa_flags = new->flags; - new_sa.sa_handler = (__sighandler_t) new->handler; - new_sa.sa_mask.__sigbits[1] = new_sa.sa_mask.__sigbits[2] = - new_sa.sa_mask.__sigbits[3] = 0; - new_sa.sa_mask.__sigbits[0] = new->sigset[0]; + __get_user(new_sa.sa_flags, &new->flags); + __get_user(new_sa.sa_handler, &(__sighandler_t) new->handler); + __get_user(new_sa.sa_mask, &new->sigset[0]); if(new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { res = verify_area(VERIFY_READ, new_sa.sa_handler, 1); @@ -368,19 +375,22 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, int res = verify_area(VERIFY_WRITE, old, sizeof(*old)); if(res) return res; - old->flags = p->sa_flags; - old->handler = (void *) p->sa_handler; - old->sigset[1] = old->sigset[2] = old->sigset[3] = 0; - old->sigset[0] = p->sa_mask.__sigbits[0]; - old->_unused0[0] = old->_unused0[1] = 0; + __put_user(p->sa_flags, &old->flags); + __put_user(p->sa_handler, &old->handler); + __put_user(p->sa_mask, &old->sigset[0]); + __put_user(0, &old->sigset[1]); + __put_user(0, &old->sigset[2]); + __put_user(0, &old->sigset[3]); + __put_user(0, &old->_unused0[0]); + __put_user(0, &old->_unused0[1]); } - if(new) { spin_lock_irq(¤t->sig->siglock); *p = new_sa; check_pending(sig); spin_unlock_irq(¤t->sig->siglock); } + return 0; } @@ -640,14 +650,14 @@ repeat: __put_user(p->pid, &info->stuff.procinfo.pid); __put_user((p->exit_code >> 8) & 0xff, &info->stuff.procinfo.procdata.child.status); - __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); - __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); + __put_user(p->times.tms_utime, &info->stuff.procinfo.procdata.child.utime); + __put_user(p->times.tms_stime, &info->stuff.procinfo.procdata.child.stime); p->exit_code = 0; retval = 0; goto end_waitsys; case TASK_ZOMBIE: - current->cutime += p->utime + p->cutime; - current->cstime += p->stime + p->cstime; + current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime; + current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime; if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); __put_user(SIGCHLD, &info->sig); @@ -655,9 +665,9 @@ repeat: __put_user(p->pid, &info->stuff.procinfo.pid); __put_user((p->exit_code >> 8) & 0xff, &info->stuff.procinfo.procdata.child.status); - __put_user(p->utime, + __put_user(p->times.tms_utime, &info->stuff.procinfo.procdata.child.utime); - __put_user(p->stime, + __put_user(p->times.tms_stime, &info->stuff.procinfo.procdata.child.stime); retval = 0; if (p->p_opptr != p->p_pptr) { @@ -855,6 +865,8 @@ asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new, out: error = 0; unlock_kernel(); + + return error; } struct irix_procset { diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index a78bc3417..0896ed1c7 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -13,6 +13,7 @@ */ #include <linux/config.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> @@ -154,11 +155,6 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) irq_enter(cpu, irq); kstat.interrupts[irq]++; -#ifdef CONFIG_SGI - prom_printf("Got irq %d, press a key.", irq); - prom_getchar(); - romvec->imode(); -#endif /* slow interrupts run with interrupts enabled */ sti(); action = *(irq + irq_action); @@ -344,7 +340,7 @@ int probe_irq_off (unsigned long irqs) return i; } -void init_IRQ(void) +__initfunc(void init_IRQ(void)) { int i; diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c index e521ecdd9..5e71233af 100644 --- a/arch/mips/kernel/pci.c +++ b/arch/mips/kernel/pci.c @@ -7,6 +7,7 @@ */ #include <linux/bios32.h> #include <linux/config.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/types.h> @@ -17,7 +18,8 @@ /* * BIOS32 replacement. */ -unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +__initfunc(unsigned long pcibios_init(unsigned long memory_start, + unsigned long memory_end)) { return memory_start; } @@ -112,7 +114,8 @@ const char *pcibios_strerror (int error) * specific implementation. */ unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end); -unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +__initfunc(unsigned long pcibios_init(unsigned long memory_start, + unsigned long memory_end)) { return _pcibios_init ? _pcibios_init(memory_start, memory_end) : memory_start; diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index f8b10bdea..08dd13c6c 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -64,16 +64,23 @@ void release_thread(struct task_struct *dead_task) { } +#define roundup(val, rnd) ({ \ + unsigned _v = val; \ + unsigned long _r = rnd; \ + _v = (_v + _r - 1) & ~(_r - 1); \ + _v; \ +}) + int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; long childksp; - childksp = p->kernel_stack_page + KERNEL_STACK_SIZE - 8; + childksp = roundup((unsigned long)p, KERNEL_STACK_SIZE) - 8; /* set up new TSS. */ - childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; + childregs = ((struct pt_regs *) ((unsigned long)p + KERNEL_STACK_SIZE)) - 1; *childregs = *regs; childregs->regs[7] = 0; /* Clear error flag */ if(current->personality == PER_LINUX) { diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 41deb8f18..e61911549 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -18,18 +18,6 @@ #include <asm/page.h> #include <asm/system.h> -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * This routine gets a long from any process space by following the page * tables. NOTE! You should check that the long isn't on a page boundary, @@ -47,7 +35,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -57,7 +45,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -67,7 +55,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -101,7 +89,7 @@ static void put_long(struct task_struct *tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -111,7 +99,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -121,12 +109,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -280,7 +268,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) res = -EPERM; goto out; } - if (!(child = get_task(pid))) { + if (!(child = find_task_by_pid(pid))) { res = -ESRCH; goto out; } diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index 83190514b..901871a31 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -9,6 +9,7 @@ #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/current.h> #include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> @@ -31,8 +32,7 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid */ .align 5 LEAF(r2300_resume) - lui t5, %hi(current_set) - lw t0, %lo(current_set)(t5) + GET_CURRENT(t0) mfc0 t1,CP0_STATUS # Save status register addu t0,a1 # Add tss offset sw t1,THREAD_STATUS(t0) @@ -50,7 +50,6 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid 1: FPU_SAVE_16EVEN(t0, t1) 2: - sw a0,%lo(current_set)(t5) # Switch current task addu a0,a1 # Add tss offset lw t0,THREAD_PGDIR(a0) # Switch the root pointer li t1,TLB_ROOT # get PFN diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S index 432c65215..5c9ad4d84 100644 --- a/arch/mips/kernel/r4k_misc.S +++ b/arch/mips/kernel/r4k_misc.S @@ -10,6 +10,7 @@ #include <asm/offset.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/current.h> #include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> @@ -29,9 +30,8 @@ */ #define LOAD_PTE(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ - lui ptr, %hi(current_set); \ srl pte, pte, 22; \ - lw ptr, %lo(current_set)(ptr); \ + GET_CURRENT(ptr); \ sll pte, pte, 2; \ lw ptr, THREAD_PGDIR(ptr); \ addu ptr, pte, ptr; \ diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 78ced5659..97e253028 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -1,4 +1,4 @@ -/* $Id: r4k_switch.S,v 1.8 1996/07/10 01:24:20 dm Exp $ +/* * r4k_switch.S: R4xx0 specific task switching code. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse @@ -9,6 +9,7 @@ #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/current.h> #include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> @@ -24,8 +25,7 @@ .set mips3 .align 5 LEAF(r4xx0_resume) - lui t5, %hi(current_set) - lw t0, %lo(current_set)(t5) + GET_CURRENT(t0) mfc0 t1, CP0_STATUS nop sw t1, THREAD_STATUS(t0) @@ -43,7 +43,6 @@ 1: FPU_SAVE_16EVEN(t0, t1) # clobbers t1 2: - sw a0, %lo(current_set)(t5) lw a3, TASK_MM(a0) lw a2, THREAD_STATUS(a0) lw a3, MM_CONTEXT(a3) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2e2b074f9..7616fa7c6 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -7,6 +7,7 @@ */ #include <linux/config.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -123,17 +124,17 @@ void (*irq_setup)(void); */ unsigned long isa_slot_offset; -static void default_irq_setup(void) +__initfunc(static void default_irq_setup(void)) { panic("Unknown machtype in init_IRQ"); } -static void default_fd_cacheflush(const void *addr, size_t size) +__initfunc(static void default_fd_cacheflush(const void *addr, size_t size)) { } -void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +__initfunc(void setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p)) { unsigned long memory_end; tag* atag; diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 848f0742b..304dc6418 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -307,7 +307,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; @@ -318,11 +321,15 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) schedule(); continue; - case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: + lock_kernel(); if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; } + unlock_kernel(); /* fall through */ default: spin_lock_irq(¤t->sigmask_lock); diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h index 4cf778acb..6c7d3988c 100644 --- a/arch/mips/kernel/syscalls.h +++ b/arch/mips/kernel/syscalls.h @@ -174,6 +174,7 @@ SYS(sys_mlock, 2) SYS(sys_munlock, 2) /* 4155 */ SYS(sys_mlockall, 1) SYS(sys_munlockall, 0) +SYS(sys_nfsservctl, 3) SYS(sys_sched_setparam,2) SYS(sys_sched_getparam,2) SYS(sys_sched_setscheduler,3) /* 4160 */ diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 9a4ddca3f..7917664fd 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -17,6 +17,8 @@ #include <linux/elf.h> #include <linux/msg.h> #include <linux/shm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/utsname.h> #include <asm/ptrace.h> @@ -24,26 +26,7 @@ #include <asm/pgtable.h> #include <asm/uaccess.h> -/* 2,000 lines of complete and utter shit coming up... */ - -/* Utility routines. */ -static inline struct task_struct *find_process_by_pid(pid_t pid) -{ - struct task_struct *p, *q; - - if (pid == 0) - p = current; - else { - p = 0; - for_each_task(q) { - if (q && q->pid == pid) { - p = q; - break; - } - } - } - return p; -} +/* 2,300 lines of complete and utter shit coming up... */ /* The sysmp commands supported thus far. */ #define MP_PGSIZE 14 /* Return system page size in v1. */ @@ -70,7 +53,6 @@ asmlinkage int irix_sysmp(struct pt_regs *regs) break; } -out: unlock_kernel(); return error; } @@ -114,7 +96,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs) printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n", current->comm, current->pid); - task = find_process_by_pid(regs->regs[base + 5]); + task = find_task_by_pid(regs->regs[base + 5]); if(!task) { error = -ESRCH; break; @@ -233,7 +215,6 @@ asmlinkage int irix_prctl(struct pt_regs *regs) break; } -out: unlock_kernel(); return error; } @@ -658,7 +639,6 @@ asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags, dev_name, dir_name, flags, type, data, datalen); ret = sys_mount(dev_name, dir_name, type, flags, data); -out: unlock_kernel(); return ret; } @@ -781,22 +761,23 @@ asmlinkage int irix_setpgrp(int flags) printk("returning %d\n", current->pgrp); #endif -out: unlock_kernel(); return error; } asmlinkage int irix_times(struct tms * tbuf) { + int error; + lock_kernel(); if (tbuf) { - int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf); + error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf); if (error) goto out; - __put_user(current->utime,&tbuf->tms_utime); - __put_user(current->stime,&tbuf->tms_stime); - __put_user(current->cutime,&tbuf->tms_cutime); - __put_user(current->cstime,&tbuf->tms_cstime); + __put_user(current->times.tms_utime,&tbuf->tms_utime); + __put_user(current->times.tms_stime,&tbuf->tms_stime); + __put_user(current->times.tms_cutime,&tbuf->tms_cutime); + __put_user(current->times.tms_cstime,&tbuf->tms_cstime); } error = 0; @@ -845,169 +826,6 @@ out: return error; } -/* sys_poll() support... */ -#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y)) - -#define POLLIN 1 -#define POLLPRI 2 -#define POLLOUT 4 -#define POLLERR 8 -#define POLLHUP 16 -#define POLLNVAL 32 -#define POLLRDNORM 64 -#define POLLWRNORM POLLOUT -#define POLLRDBAND 128 -#define POLLWRBAND 256 - -#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN) -#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT) -#define LINUX_POLLERR (POLLERR) - -static inline void free_wait(select_table * p) -{ - struct select_table_entry * entry = p->entry + p->nr; - - while (p->nr > 0) { - p->nr--; - entry--; - remove_wait_queue(entry->wait_address,&entry->wait); - } -} - - -/* Copied directly from fs/select.c */ -static int check(int flag, select_table * wait, struct file * file) -{ - struct inode * inode; - struct file_operations *fops; - int (*select) (struct inode *, struct file *, int, select_table *); - - inode = file->f_inode; - if ((fops = file->f_op) && (select = fops->select)) - return select(inode, file, flag, wait) - || (wait && select(inode, file, flag, NULL)); - if (S_ISREG(inode->i_mode)) - return 1; - return 0; -} - -struct poll { - int fd; - short events; - short revents; -}; - -int irix_poll(struct poll * ufds, size_t nfds, int timeout) -{ - int i,j, count, fdcount, error, retflag; - struct poll * fdpnt; - struct poll * fds, *fds1; - select_table wait_table, *wait; - struct select_table_entry *entry; - - lock_kernel(); - if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll)))) - goto out; - - if (nfds > NR_OPEN) { - error = -EINVAL; - goto out; - } - - if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL)) - || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) { - error = -ENOMEM; - goto out; - } - - copy_from_user(fds, ufds, nfds*sizeof(struct poll)); - - if (timeout < 0) - current->timeout = 0x7fffffff; - else { - current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ)); - if (current->timeout <= jiffies) - current->timeout = 0; - } - - count = 0; - wait_table.nr = 0; - wait_table.entry = entry; - wait = &wait_table; - - for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { - i = fdpnt->fd; - fdpnt->revents = 0; - if (!current->files->fd[i] || !current->files->fd[i]->f_inode) - fdpnt->revents = POLLNVAL; - } -repeat: - current->state = TASK_INTERRUPTIBLE; - for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { - i = fdpnt->fd; - - if(i < 0) continue; - if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue; - - if ((fdpnt->events & LINUX_POLLIN) - && check(SEL_IN, wait, current->files->fd[i])) { - retflag = 0; - if (fdpnt->events & POLLIN) - retflag = POLLIN; - if (fdpnt->events & POLLRDNORM) - retflag = POLLRDNORM; - fdpnt->revents |= retflag; - count++; - wait = NULL; - } - - if ((fdpnt->events & LINUX_POLLOUT) && - check(SEL_OUT, wait, current->files->fd[i])) { - fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events); - count++; - wait = NULL; - } - - if (check(SEL_EX, wait, current->files->fd[i])) { - fdpnt->revents |= POLLHUP; - count++; - wait = NULL; - } - } - - if ((current->signal & (~current->blocked))) { - error = -EINTR; - goto out; - } - - wait = NULL; - if (!count && current->timeout > jiffies) { - schedule(); - goto repeat; - } - - free_wait(&wait_table); - free_page((unsigned long) entry); - - /* OK, now copy the revents fields back to user space. */ - fds1 = fds; - fdcount = 0; - for(i=0; i < (int)nfds; i++, ufds++, fds++) { - if (fds->revents) { - fdcount++; - } - put_user(fds->revents, &ufds->revents); - } - kfree(fds1); - current->timeout = 0; - current->state = TASK_RUNNING; - error = fdcount; - -out: - unlock_kernel(); - return error; -} - asmlinkage unsigned long irix_gethostid(void) { lock_kernel(); @@ -1263,7 +1081,6 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp) printk("error = %d\n", error); #endif -out: unlock_kernel(); return error; } @@ -1443,11 +1260,11 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) if(error) goto out; error = irix_xstat32_xlate(&kb, statbuf); - goto error; + goto out; } case 3: { - sys_newlstat(filename, statbuf); + error = sys_newlstat(filename, statbuf); #ifdef DEBUG_XSTAT printk("error[%d]\n", error); #endif @@ -1456,7 +1273,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) irix_xstat64_xlate(statbuf); error = 0; - goto error; + goto out; } default: @@ -1466,7 +1283,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) out: unlock_kernel(); - return errno; + return error; } extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); @@ -2018,13 +1835,13 @@ out: asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf) { - int errno; + int error; lock_kernel(); printk("[%s:%d] irix_getmountid(%s, %p)\n", current->comm, current->pid, fname, midbuf); - errno = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4)); - if(errno) + error = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4)); + if(error) goto out; /* @@ -2142,7 +1959,7 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32); if (error < 0) - goto out + goto out; lastdirent = buf.previous; if (!lastdirent) { error = buf.error; @@ -2431,6 +2248,8 @@ asmlinkage int irix_fcntl(int fd, int cmd, int arg) asmlinkage int irix_ulimit(int cmd, int arg) { + int retval; + lock_kernel(); switch(cmd) { case 1: diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index aa4547456..fd57f6d0e 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -7,6 +7,7 @@ * found in some MIPS systems. */ #include <linux/errno.h> +#include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/param.h> @@ -299,7 +300,7 @@ static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}; void (*board_time_init)(struct irqaction *irq); -void time_init(void) +__initfunc(void time_init(void)) { unsigned int year, mon, day, hour, min, sec; int i; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 17b1f9a28..cdbcacb43 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -17,6 +17,7 @@ * Modified for R3000 by Paul M. Antoine, 1995, 1996 */ #include <linux/config.h> +#include <linux/init.h> #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> @@ -110,10 +111,8 @@ void show_registers(char * str, struct pt_regs * regs, long err) /* * Dump the stack */ - if (STACK_MAGIC != *(u32 *)current->kernel_stack_page) - printk("Corrupted stack page\n"); printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, current->kernel_stack_page); + current->comm, current->pid, (unsigned long)current); for(i=0;i<5;i++) printk("%08x ", *sp++); stack = (int *) sp; @@ -389,7 +388,7 @@ void do_reserved(struct pt_regs *regs) unlock_kernel(); } -static void watch_init(unsigned long cputype) +static inline void watch_init(unsigned long cputype) { switch(cputype) { case CPU_R10000: @@ -427,7 +426,7 @@ extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc); extern asmlinkage void r4xx0_resume(void *tsk); extern asmlinkage void r2300_resume(void *tsk); -void trap_init(void) +__initfunc(void trap_init(void)) { extern char except_vec0_r4000, except_vec0_r4600, except_vec0_r2300; extern char except_vec1_generic, except_vec2_generic; diff --git a/arch/mips/mips/Makefile b/arch/mips/mips/Makefile new file mode 100644 index 000000000..b252e2fe4 --- /dev/null +++ b/arch/mips/mips/Makefile @@ -0,0 +1,39 @@ +# +# PROM Entries for the big endian firmware used in the Mips Computer +# System, Inc. machines. Beware: some of the machines seem to be +# different. +# +# Copyright (C) 1997 Ralf Baechle +# +prom-entries= reset exec restart reinit reboot autoboot open read write ioctl \ + close getchar putchar showchar gets puts printf initproto protoenable \ + protodisable getpkt putpkt orw_rmw orh_rmw orb_rmw andw_rmw andh_rmw \ + andb_rmw flushcache clearcache setjmp longjmp bevutlb getenv setenv \ + atob strcmp strlen strcpy strcat parser range argvize help dumpcmd \ + setenvcmd unsetenvcmd printenvcmd bevexcept enablecmd disablecmd \ + clearnofault notimplement nv_get nv_set +asm-files=$(addsuffix .S,$(prom-entries)) +object-files=$(addsuffix .o,$(prom-entries)) + +CC=mipsel-linux-gcc +AR=mipsel-linux-ar +CFLAGS=-O2 -mno-abicalls -fno-pic -G0 -Wall + +all: libprom.a + +libprom.a: $(asm-files) + set -e;for i in $(prom-entries); do \ + $(CC) $(CFLAGS) -c -o $$i.o $$i.S; \ + $(AR) rcv libprom.a $$i.o; \ + done + +$(asm-files): mkprom + set -e;for i in $(prom-entries); do \ + mkprom $$i; \ + done + +clean: + rm -f $(object-files) + +distclean: + rm -rf $(asm-files) libprom.a diff --git a/arch/mips/mips/mkprom b/arch/mips/mips/mkprom new file mode 100755 index 000000000..9e4cdf465 --- /dev/null +++ b/arch/mips/mips/mkprom @@ -0,0 +1,25 @@ +# +# Generate PROM library stubs for the firmware used in the +# Mips Computer System, Inc. machines. Beware: some of the +# machines seem to be different. +# +# Copyright (C) 1997 Ralf Baechle +# +fname=$1 +ucase=`echo $fname | tr 'a-z' 'A-Z'` +cat << EOF | sed -e "s/@1@/$fname/" -e "s/@2@/$ucase/" >$fname.S +/* + * WARNING: This file has been generated automatically. Do not edit! + * + * Stub for the Mips firmware @1@() function. + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsprom.h> + +LEAF(mips_prom_@1@) + lw t0,__mips_prom_entry_offset + addu t0,PROM_@2@ + jr t0 + END(mips_prom_@1@) +EOF diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index d12159903..1205b2bf3 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -9,6 +9,6 @@ O_TARGET := mm.o O_OBJS := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \ - andes.o loadmmu.o stack.o + andes.o loadmmu.o include $(TOPDIR)/Rules.make diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 4fdd98155..3ad703b1f 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -70,7 +70,7 @@ good_area: if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(vma, address, writeaccess); + handle_mm_fault(tsk, vma, address, writeaccess); up(&mm->mmap_sem); goto out; diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c index 5f1bcbfa6..f83f41df8 100644 --- a/arch/mips/mm/r4xx0.c +++ b/arch/mips/mm/r4xx0.c @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.19 1996/08/02 11:11:36 dm Exp $ +/* * r4xx0.c: R4000 processor variant specific MMU/Cache routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -325,28 +325,6 @@ static inline void r4k_flush_cache_all_d32i32(void) restore_flags(flags); } -static inline struct vm_area_struct * -find_mm_vma(struct mm_struct *mm, unsigned long addr) -{ - struct vm_area_struct * result = NULL; - - if (mm) { - struct vm_area_struct * tree = mm->mmap_avl; - for (;;) { - if (tree == avl_empty) - break; - if (tree->vm_end > addr) { - result = tree; - if (tree->vm_start <= addr) - break; - tree = tree->vm_avl_left; - } else - tree = tree->vm_avl_right; - } - } - return result; -} - static void r4k_flush_cache_range_s16d16i16(struct mm_struct *mm, unsigned long start, @@ -362,7 +340,7 @@ r4k_flush_cache_range_s16d16i16(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s16d16i16(); @@ -407,7 +385,7 @@ r4k_flush_cache_range_s32d16i16(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s32d16i16(); @@ -451,7 +429,7 @@ static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s64d16i16(); @@ -495,7 +473,7 @@ static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s128d16i16(); @@ -539,7 +517,7 @@ static void r4k_flush_cache_range_s16d32i32(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s16d32i32(); @@ -583,7 +561,7 @@ static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s32d32i32(); @@ -627,7 +605,7 @@ static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s64d32i32(); @@ -671,7 +649,7 @@ static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - vma = find_mm_vma(mm, start); + vma = find_vma(mm, start); if(vma) { if(mm->context != current->mm->context) { r4k_flush_cache_all_s128d32i32(); diff --git a/arch/mips/mm/stack.c b/arch/mips/mm/stack.c deleted file mode 100644 index 89fb6dc64..000000000 --- a/arch/mips/mm/stack.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Kernel stack allocation/deallocation - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996, 1997 by Ralf Baechle - * - * (This is _bad_ if the free page pool is fragmented ...) - */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <asm/processor.h> - -extern unsigned long alloc_kernel_stack(struct task_struct *tsk) -{ - unsigned long stack; - stack = __get_free_pages(GFP_KERNEL, 1, 0); - - return stack; -} - -extern void free_kernel_stack(unsigned long stack) -{ - free_pages(stack, 1); -} diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c index 19b744fdb..fe60c03c8 100644 --- a/arch/mips/sgi/kernel/indy_int.c +++ b/arch/mips/sgi/kernel/indy_int.c @@ -16,6 +16,8 @@ #include <linux/timex.h> #include <linux/malloc.h> #include <linux/random.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <asm/bitops.h> #include <asm/bootinfo.h> @@ -51,6 +53,7 @@ extern asmlinkage void indyIRQ(void); extern void rs_kgdb_hook(int); #endif +unsigned int local_irq_count[NR_CPUS]; unsigned long spurious_count = 0; /* Local IRQ's are layed out logically like this: @@ -255,6 +258,15 @@ int get_irq_list(char *buf) return len; } +atomic_t __mips_bh_counter; + +#ifdef __SMP__ +#error Send superfluous SMP boxes to ralf@uni-koblenz.de +#else +#define irq_enter(cpu, irq) (++local_irq_count[cpu]) +#define irq_exit(cpu, irq) (--local_irq_count[cpu]) +#endif + /* * do_IRQ handles IRQ's that have been installed without the * SA_INTERRUPT flag: it uses the full signal-handling return @@ -264,8 +276,9 @@ int get_irq_list(char *buf) */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { - lock_kernel(); struct irqaction * action = *(irq + irq_action); + + lock_kernel(); kstat.interrupts[irq]++; printk("Got irq %d, press a key.", irq); prom_getchar(); diff --git a/arch/mips/sgi/kernel/setup.c b/arch/mips/sgi/kernel/setup.c index 58b7695b3..e0482e116 100644 --- a/arch/mips/sgi/kernel/setup.c +++ b/arch/mips/sgi/kernel/setup.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/sched.h> +#include <asm/reboot.h> #include <asm/vector.h> #include <asm/sgialib.h> #include <asm/sgi.h> diff --git a/arch/mips/sgi/prom/misc.c b/arch/mips/sgi/prom/misc.c index 47051a1b3..53ee61cfe 100644 --- a/arch/mips/sgi/prom/misc.c +++ b/arch/mips/sgi/prom/misc.c @@ -1,9 +1,9 @@ -/* $Id: misc.c,v 1.3 1996/08/07 02:54:12 dm Exp $ +/* * misc.c: Miscellaneous ARCS PROM routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ - +#include <linux/config.h> #include <linux/kernel.h> #include <asm/sgialib.h> @@ -51,7 +51,9 @@ void prom_halt(void) { shutoff_r4600_cache(); initialize_kbd(); +#if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); +#endif cli(); romvec->halt(); } @@ -60,7 +62,9 @@ void prom_powerdown(void) { shutoff_r4600_cache(); initialize_kbd(); +#if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); +#endif cli(); romvec->pdown(); } @@ -70,7 +74,9 @@ void prom_restart(void) { shutoff_r4600_cache(); initialize_kbd(); +#if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); +#endif cli(); romvec->restart(); } @@ -79,7 +85,9 @@ void prom_reboot(void) { shutoff_r4600_cache(); initialize_kbd(); +#if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); +#endif cli(); romvec->reboot(); } @@ -88,7 +96,9 @@ void prom_imode(void) { shutoff_r4600_cache(); initialize_kbd(); +#if CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); +#endif cli(); romvec->imode(); } diff --git a/arch/mips/sni/.cvsignore b/arch/mips/sni/.cvsignore new file mode 100644 index 000000000..4671378ae --- /dev/null +++ b/arch/mips/sni/.cvsignore @@ -0,0 +1 @@ +.depend diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile index f0bc3e600..9bd570ff0 100644 --- a/arch/mips/sni/Makefile +++ b/arch/mips/sni/Makefile @@ -13,7 +13,7 @@ all: sni.o O_TARGET := sni.o -O_OBJS := hw-access.o int-handler.o pci.o reset.o setup.o +O_OBJS := hw-access.o int-handler.o io.o pci.o reset.o setup.o int-handler.o: int-handler.S diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S index f60c82251..d051c8b13 100644 --- a/arch/mips/sni/int-handler.S +++ b/arch/mips/sni/int-handler.S @@ -1,7 +1,7 @@ /* * SNI RM200 PCI specific interrupt handler code. * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle + * Copyright (C) 1994 - 1997 by Ralf Baechle */ #include <asm/asm.h> #include <linux/config.h> @@ -150,30 +150,17 @@ poll_second: li a0,0x0f #endif /* CONFIG_PCNET32 */ -/* - * FIXME: This is definatly wrong but I'll have to do it this way - * 'till I get more hardware info. - * XXX: Apparently the NCR is attached to interrupt #2. - */ #ifdef CONFIG_SCSI_NCR53C8XX /* - * FIXME: detect this address - */ -#define NCR_BASE 0xb8000000 - -/* Offsets from base I/O address. */ -#define NCR_INTF 0x14 - -/* * ... check if we were interrupted by the NCR ... */ -3: lb t0,NCR_BASE+NCR_INTF - andi t0,7 - beqz t0,3f # no NCR interrupt? +3: lb t0,PCIMT_CSITPEND + andi t0,0x40 + bnez t0,3f # bit 6 == 0 -> SCSI IRQ nop # delay slot jal do_fast_IRQ - li a0,5 # delay slot + li a0,PCIMT_IRQ_SCSI # delay slot j return nop # delay slot diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c new file mode 100644 index 000000000..f62fdc2d7 --- /dev/null +++ b/arch/mips/sni/io.c @@ -0,0 +1,172 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Low level I/O functions for SNI. + */ +#include <linux/string.h> +#include <asm/mipsconfig.h> +#include <asm/addrspace.h> +#include <asm/system.h> +#include <asm/spinlock.h> +#include <asm/sni.h> + +unsigned char sni_map_isa_cache; + +#define unused __attribute__((unused)) + +/* + * The PCIMT_CSMAPISA is shared by all processors; we need locking. + * + * XXX It's legal to use all the I/O memory access functions in interrupt + * code, so we need to use the _irq locking stuff which may result in + * significant IRQ latencies. + */ +static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED; + +/* + * Urgs... We only can see a 16mb window of the 4gb EISA address space + * at PCIMT_EISA_BASE. Maladia segmentitis ... + * + * XXX Check out if accessing PCIMT_CSMAPISA really is slow. + * For now assume so. + */ +static inline void update_isa_cache(unsigned long address) +{ + unsigned char upper; + + upper = address >> 24; + if (sni_map_isa_cache != upper) { + sni_map_isa_cache = upper; + *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper; + } +} + +static unsigned char sni_readb(unsigned long addr) +{ + unsigned char res; + + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); + spin_unlock_irq(&csmapisa_lock); + + return res; +} + +static unsigned short sni_readw(unsigned long addr) +{ + unsigned short res; + + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); + spin_unlock_irq(&csmapisa_lock); + + return res; +} + +static unsigned int sni_readl(unsigned long addr) +{ + unsigned int res; + + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); + spin_unlock_irq(&csmapisa_lock); + + return res; +} + +static void sni_writeb(unsigned char val, unsigned long addr) +{ + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; + spin_unlock_irq(&csmapisa_lock); +} + +static void sni_writew(unsigned short val, unsigned long addr) +{ + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; + spin_unlock_irq(&csmapisa_lock); +} + +static void sni_writel(unsigned int val, unsigned long addr) +{ + spin_lock_irq(&csmapisa_lock); + update_isa_cache(addr); + addr &= 0xffffff; + *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; + spin_unlock_irq(&csmapisa_lock); +} + +static void sni_memset_io(unsigned long addr, int val, unsigned long len) +{ + unsigned long waddr; + + waddr = PCIMT_EISA_BASE | (addr & 0xffffff); + spin_lock_irq(&csmapisa_lock); + while(len) { + unsigned long fraglen; + + fraglen = (~addr + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + update_isa_cache(addr); + memset((char *)waddr, val, fraglen); + addr += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } + spin_unlock_irq(&csmapisa_lock); +} + +static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len) +{ + unsigned long waddr; + + waddr = PCIMT_EISA_BASE | (from & 0xffffff); + spin_lock_irq(&csmapisa_lock); + while(len) { + unsigned long fraglen; + + fraglen = (~from + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + update_isa_cache(from); + memcpy((void *)to, (void *)waddr, fraglen); + to += fraglen; + from += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } + spin_unlock_irq(&csmapisa_lock); +} + +static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len) +{ + unsigned long waddr; + + waddr = PCIMT_EISA_BASE | (to & 0xffffff); + spin_lock_irq(&csmapisa_lock); + while(len) { + unsigned long fraglen; + + fraglen = (~to + 1) & 0xffffff; + fraglen = (fraglen < len) ? fraglen : len; + update_isa_cache(to); + memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen); + to += fraglen; + from += fraglen; + waddr = waddr + fraglen - 0x1000000; + len -= fraglen; + } + spin_unlock_irq(&csmapisa_lock); +} diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c index 06edb268f..917d07a81 100644 --- a/arch/mips/sni/pci.c +++ b/arch/mips/sni/pci.c @@ -7,6 +7,7 @@ */ #include <linux/config.h> #include <linux/bios32.h> +#include <linux/init.h> #include <linux/pci.h> #include <linux/types.h> #include <asm/byteorder.h> @@ -18,18 +19,26 @@ extern inline u32 mkaddr(unsigned char bus, unsigned char dev_fn, unsigned char where) { - return (((bus & 0xff) << 0x10) | - ((dev_fn & 0xff) << 0x08) | - ((where & 0xfc))); + return ((bus & 0xff) << 0x10) | + ((dev_fn & 0xff) << 0x08) | + (where & 0xfc); } static unsigned long sni_rm200_pcibios_fixup (unsigned long memory_start, unsigned long memory_end) { - /* I guess it's ok to do exactly nothing. */ + /* + * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards. + * Take care of RM300 revision D boards for where the network + * slot became an ordinary PCI slot. + */ return memory_start; } +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ static int sni_rm200_pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, unsigned char where, @@ -39,7 +48,7 @@ static int sni_rm200_pcibios_read_config_byte (unsigned char bus, *(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where); res = *(volatile u32 *)PCIMT_CONFIG_DATA; - res = le32_to_cpu(res); + res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff; *val = res; return PCIBIOS_SUCCESSFUL; @@ -56,7 +65,7 @@ static int sni_rm200_pcibios_read_config_word (unsigned char bus, return PCIBIOS_BAD_REGISTER_NUMBER; *(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where); res = *(volatile u32 *)PCIMT_CONFIG_DATA; - res = le32_to_cpu(res); + res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff; *val = res; return PCIBIOS_SUCCESSFUL; @@ -110,7 +119,7 @@ static int sni_rm200_pcibios_write_config_dword (unsigned char bus, return PCIBIOS_SUCCESSFUL; } -unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end) +__initfunc(unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end)) { _pcibios_fixup = sni_rm200_pcibios_fixup; _pcibios_read_config_byte = sni_rm200_pcibios_read_config_byte; diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 1a7a1387d..7fa76a490 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -5,11 +5,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 1997 by Ralf Baechle */ #include <asm/ptrace.h> #include <linux/ioport.h> #include <linux/sched.h> +#include <linux/init.h> #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/pci.h> @@ -40,8 +41,7 @@ extern void sni_machine_restart(char *command); extern void sni_machine_halt(void); extern void sni_machine_power_off(void); -static void -sni_irq_setup(void) +__initfunc(static void sni_irq_setup(void)) { set_except_vector(0, sni_rm200_pci_handle_int); request_region(0x20,0x20, "pic1"); @@ -57,7 +57,7 @@ sni_irq_setup(void) void (*board_time_init)(struct irqaction *irq); -static void sni_rm200_pci_time_init(struct irqaction *irq) +__initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq)) { /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ @@ -67,8 +67,9 @@ static void sni_rm200_pci_time_init(struct irqaction *irq) } unsigned char aux_device_present; -unsigned long sni_rm200_pcibios_init (unsigned long memory_start, - unsigned long memory_end); +extern unsigned long sni_rm200_pcibios_init (unsigned long memory_start, + unsigned long memory_end); +extern unsigned char sni_map_isa_cache; /* * A bit more gossip about the iron we're running on ... @@ -92,8 +93,7 @@ static inline void sni_pcimt_detect(void) printk("%s.\n", boardtype); } -void -sni_rm200_pci_setup(void) +__initfunc(void sni_rm200_pci_setup(void)) { tag *atag; @@ -127,7 +127,14 @@ sni_rm200_pci_setup(void) fd_cacheflush = sni_fd_cacheflush; // Will go away feature = &sni_rm200_pci_feature; port_base = SNI_PORT_BASE; + + /* + * Setup (E)ISA I/O memory access stuff + */ isa_slot_offset = 0xb0000000; + // sni_map_isa_cache = 0; + EISA_bus = 1; + request_region(0x00,0x20,"dma1"); request_region(0x40,0x20,"timer"); /* XXX FIXME: CONFIG_RTC */ @@ -140,8 +147,6 @@ sni_rm200_pci_setup(void) _machine_halt = sni_machine_halt; _machine_power_off = sni_machine_power_off; - if (mips_machtype == MACH_SNI_RM200_PCI) - EISA_bus = 1; aux_device_present = 0xaa; /* diff --git a/arch/mips/tools/.cvsignore b/arch/mips/tools/.cvsignore new file mode 100644 index 000000000..2a1642034 --- /dev/null +++ b/arch/mips/tools/.cvsignore @@ -0,0 +1 @@ +.depend offset.s offset.h diff --git a/arch/mips/tools/offset.c b/arch/mips/tools/offset.c index 3bb46de6e..a8660dcf6 100644 --- a/arch/mips/tools/offset.c +++ b/arch/mips/tools/offset.c @@ -77,12 +77,11 @@ void output_task_defines(void) { text("/* MIPS task_struct offsets. */"); offset("#define TASK_STATE ", struct task_struct, state); + offset("#define TASK_COUNTER ", struct task_struct, counter); offset("#define TASK_PRIORITY ", struct task_struct, priority); offset("#define TASK_SIGNAL ", struct task_struct, signal); offset("#define TASK_BLOCKED ", struct task_struct, blocked); offset("#define TASK_FLAGS ", struct task_struct, flags); - offset("#define TASK_SAVED_KSTACK ", struct task_struct, saved_kernel_stack); - offset("#define TASK_KSTACK_PG ", struct task_struct, kernel_stack_page); offset("#define TASK_MM ", struct task_struct, mm); linefeed; } diff --git a/arch/mips/tools/offset.h b/arch/mips/tools/offset.h deleted file mode 100644 index c5e6f37fa..000000000 --- a/arch/mips/tools/offset.h +++ /dev/null @@ -1,89 +0,0 @@ -/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */ - -#ifndef _MIPS_OFFSET_H -#define _MIPS_OFFSET_H - -/* MIPS pt_regs offsets. */ -#define PT_R0 24 -#define PT_R1 28 -#define PT_R2 32 -#define PT_R3 36 -#define PT_R4 40 -#define PT_R5 44 -#define PT_R6 48 -#define PT_R7 52 -#define PT_R8 56 -#define PT_R9 60 -#define PT_R10 64 -#define PT_R11 68 -#define PT_R12 72 -#define PT_R13 76 -#define PT_R14 80 -#define PT_R15 84 -#define PT_R16 88 -#define PT_R17 92 -#define PT_R18 96 -#define PT_R19 100 -#define PT_R20 104 -#define PT_R21 108 -#define PT_R22 112 -#define PT_R23 116 -#define PT_R24 120 -#define PT_R25 124 -#define PT_R26 128 -#define PT_R27 132 -#define PT_R28 136 -#define PT_R29 140 -#define PT_R30 144 -#define PT_R31 148 -#define PT_LO 152 -#define PT_HI 156 -#define PT_OR2 160 -#define PT_OR7 164 -#define PT_EPC 168 -#define PT_BVADDR 172 -#define PT_STATUS 176 -#define PT_CAUSE 180 -#define PT_SIZE 184 - -/* MIPS task_struct offsets. */ -#define TASK_STATE 0 -#define TASK_PRIORITY 8 -#define TASK_SIGNAL 12 -#define TASK_BLOCKED 16 -#define TASK_FLAGS 20 -#define TASK_SAVED_KSTACK 84 -#define TASK_KSTACK_PG 88 -#define TASK_MM 912 - -/* MIPS specific thread_struct offsets. */ -#define THREAD_REG16 544 -#define THREAD_REG17 548 -#define THREAD_REG18 552 -#define THREAD_REG19 556 -#define THREAD_REG20 560 -#define THREAD_REG21 564 -#define THREAD_REG22 568 -#define THREAD_REG23 572 -#define THREAD_REG28 576 -#define THREAD_REG29 580 -#define THREAD_REG30 584 -#define THREAD_REG31 588 -#define THREAD_STATUS 592 -#define THREAD_FPU 600 -#define THREAD_BVADDR 864 -#define THREAD_ECODE 868 -#define THREAD_TRAPNO 872 -#define THREAD_KSP 876 -#define THREAD_PGDIR 880 -#define THREAD_MFLAGS 884 -#define THREAD_CURDS 888 -#define THREAD_TRAMP 892 -#define THREAD_OLDCTX 896 - -/* Linux mm_struct offsets. */ -#define MM_COUNT 0 -#define MM_PGD 4 -#define MM_CONTEXT 8 - -#endif /* !(_MIPS_OFFSET_H) */ diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index e137e1171..c2a2989ec 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -855,5 +855,6 @@ sys_call_table: .long sys_mremap .long SYMBOL_NAME(sys_setresuid) .long SYMBOL_NAME(sys_getresuid) - .space (NR_syscalls-165)*4 + .long SYMBOL_NAME(sys_nfsservctl) + .space (NR_syscalls-166)*4 diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 8dc0e61ca..ee21c5cbe 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -29,6 +29,24 @@ #include <asm/io.h> #include <asm/ppc_machine.h> + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ +static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, }; +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; + +struct mm_struct init_mm = INIT_MM; +struct task_struct init_task = INIT_TASK; + + int dump_fpu(void); void hard_reset_now(void); void switch_to(struct task_struct *, struct task_struct *); diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 2d960c8cd..dc8a95302 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -42,18 +42,6 @@ static int regoff[] = { }; -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -394,7 +382,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 6a6ffdb89..ee2381dba 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -58,69 +58,62 @@ pte_t __bad_page(void) void show_mem(void) { - unsigned long i,free = 0,total = 0,reserved = 0; - unsigned long shared = 0; - PTE *ptr; - unsigned long full = 0, overflow = 0; - unsigned int ti; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = MAP_NR(high_memory); - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (!atomic_read(&mem_map[i].count)) - free++; - else - shared += atomic_read(&mem_map[i].count) - 1; - } - printk("%lu pages of RAM\n",total); - printk("%lu free pages\n",free); - printk("%lu reserved pages\n",reserved); - printk("%lu pages shared\n",shared); - show_buffers(); + struct task_struct *p; + unsigned long i,free = 0,total = 0,reserved = 0; + unsigned long shared = 0; + PTE *ptr; + unsigned long full = 0, overflow = 0; + unsigned int ti; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = MAP_NR(high_memory); + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (!atomic_read(&mem_map[i].count)) + free++; + else + shared += atomic_read(&mem_map[i].count) - 1; + } + printk("%lu pages of RAM\n",total); + printk("%lu free pages\n",free); + printk("%lu reserved pages\n",reserved); + printk("%lu pages shared\n",shared); + show_buffers(); #ifdef CONFIG_NET - show_net_buffers(); + show_net_buffers(); #endif #ifdef HASHSTATS - printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8); - for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) - { - if ( hashhits[i] >= 20 ) - { - printk("[%lu] \t %lu\n", i,hashhits[i]); - } - } + printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8); + for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) { + if ( hashhits[i] >= 20 ) + printk("[%lu] \t %lu\n", i,hashhits[i]); + } #endif - for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) - { - if (ptr->v) - { - full++; - if (ptr->h == 1) - overflow++; - } - } - printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n", - Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10, - full,Hash_size/sizeof(PTE), - (full*100)/(Hash_size/sizeof(PTE)), - overflow); - printk(" Task context vsid0\n"); - for ( ti = 0; ti < NR_TASKS ; ti++ ); - { - if ( task[ti] ) - { - printk("%5d %8x %8x\n", - task[ti]->pid,task[ti]->mm->context, - ((SEGREG *)task[ti]->tss.segs)[0].vsid); - } - } - + for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) { + if (ptr->v) { + full++; + if (ptr->h == 1) + overflow++; + } + } + printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n", + Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10, + full,Hash_size/sizeof(PTE), + (full*100)/(Hash_size/sizeof(PTE)), + overflow); + printk(" Task context vsid0\n"); + read_lock(&tasklist_lock); + for_each_task(p) { + printk("%5d %8x %8x\n", + p->pid,p->mm->context, + ((SEGREG *)p->tss.segs)[0].vsid); + } + read_unlock(&tasklist_lock); } extern unsigned long free_area_init(unsigned long, unsigned long); diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 587cfc616..92c73de32 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $ +# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -21,7 +21,7 @@ CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7 #LINKFLAGS = -N -Ttext 0xf0004000 LINKFLAGS = -T arch/sparc/vmlinux.lds -HEAD := arch/sparc/kernel/head.o +HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \ arch/sparc/prom diff --git a/arch/sparc/ap1000/bnet.c b/arch/sparc/ap1000/bnet.c index 9305b0a55..974501d79 100644 --- a/arch/sparc/ap1000/bnet.c +++ b/arch/sparc/ap1000/bnet.c @@ -872,12 +872,12 @@ static void reply_kill(struct cap_request *req) len = req->size - sizeof(*req); if (len == 0) { int pid = req->data[1]; - for_each_task(p) - if (p->pid == pid) { - send_sig(sig,p,1); - return; - } - printk("cell %d: no task with pid %d\n",mpp_cid(),pid); + p = find_task_by_pid(pid); + + if(p) + send_sig(sig, p, 1); + else + printk("cell %d: no task with pid %d\n",mpp_cid(),pid); return; } @@ -889,9 +889,11 @@ static void reply_kill(struct cap_request *req) read_bif(name,len); name[len] = 0; + read_lock(&tasklist_lock); for_each_task(p) if (strcmp(name,p->comm) == 0) send_sig(sig,p,1); + read_unlock(&tasklist_lock); } diff --git a/arch/sparc/ap1000/hw.c b/arch/sparc/ap1000/hw.c index c36150c4e..aabe15a3b 100644 --- a/arch/sparc/ap1000/hw.c +++ b/arch/sparc/ap1000/hw.c @@ -86,14 +86,21 @@ static void show_task(struct task_struct *t) static void show_ptasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; - for (i=MPP_TASK_BASE;i<NR_TASKS;i++) - if (task[i]) { - show_task(task[i]); + read_lock(&tasklist_lock); + for_each_task(p) { + struct task_struct **tp = p->tarray_ptr; + + if(tp >= &task[MPP_TASK_BASE]) { + show_task(p); count++; } + } + read_unlock(&tasklist_lock); + if (count == 0) printk("no parallel tasks on cell %d\n",mpp_cid()); } @@ -101,14 +108,18 @@ static void show_ptasks(void) static void show_utasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; - for (i=0;i<NR_TASKS;i++) - if (task[i] && task[i]->uid > 1) { + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->uid > 1) { show_task(task[i]); count++; } + } + read_unlock(&tasklist_lock); if (count == 0) printk("no user tasks on cell %d\n",mpp_cid()); @@ -118,15 +129,19 @@ static void show_utasks(void) static void show_otasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; extern int ap_current_uid; - for (i=0;i<NR_TASKS;i++) - if (task[i] && task[i]->uid == ap_current_uid) { + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->uid == ap_current_uid) { show_task(task[i]); count++; } + } + read_unlock(&tasklist_lock); if (count == 0) printk("no tasks on cell %d\n",mpp_cid()); diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c index 021c1a2e5..84ef7f28e 100644 --- a/arch/sparc/ap1000/mpp.c +++ b/arch/sparc/ap1000/mpp.c @@ -66,6 +66,7 @@ int mpp_weight(struct task_struct *tsk) if (block_parallel_tasks) return -1000; + /* XXX task[] fixme */ if (last_task && last_task != tsk->taskid && task[last_task] && !msc_switch_ok()) return -1000; diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index f73a52fb3..d3307e463 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $ +# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -28,7 +28,7 @@ else CHECKASM_CC = $(CC) endif -all: kernel.o head.o +all: kernel.o head.o init_task.o O_TARGET := kernel.o IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S index b93094919..fc6c4cead 100644 --- a/arch/sparc/kernel/etrap.S +++ b/arch/sparc/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $ +/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -129,15 +129,23 @@ tsetup_patch2: trap_setup_from_user: /* We can't use %curptr yet. */ LOAD_CURRENT(t_kstack, t_twinmask) + + mov 1, %t_twinmask + sll %t_twinmask, (PAGE_SHIFT + 1), %t_twinmask + sub %t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask + add %t_kstack, %t_twinmask, %t_kstack + mov 1, %t_twinmask - ld [%t_kstack + AOFF_task_saved_kernel_stack], %t_kstack sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr) /* Build pt_regs frame. */ STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2) /* Clear current->tss.w_saved */ - LOAD_CURRENT(curptr, g1) + mov 1, %curptr + sll %curptr, (PAGE_SHIFT + 1), %curptr + sub %curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr + sub %t_kstack, %curptr, %curptr st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] /* See if we are in the trap window. */ diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index eea3528bf..90965e26e 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.81 1997/04/16 07:15:48 davem Exp $ +/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -393,12 +393,6 @@ C_LABEL(trapbase_cpu3): BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) - .globl C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack) - .globl C_LABEL(cpu3_stack) -C_LABEL(cpu0_stack): .skip 0x2000 -C_LABEL(cpu1_stack): .skip 0x2000 -C_LABEL(cpu2_stack): .skip 0x2000 -C_LABEL(cpu3_stack): .skip 0x2000 #endif .skip 4096 @@ -742,6 +736,9 @@ go_to_highmem: jmpl %g1, %g0 nop + /* This is to align init_task_union properly, be careful. -DaveM */ + .align 8192 + /* The code above should be at beginning and we have to take care about * short jumps, as branching to .text.init section from .text is usually * impossible */ @@ -986,12 +983,10 @@ sun4c_continue_boot: /* Initialize the umask value for init_task just in case. * But first make current_set[0] point to something useful. */ - set C_LABEL(init_task), %g6 + set C_LABEL(init_task_union), %g6 set C_LABEL(current_set), %g2 st %g6, [%g2] - set C_LABEL(bootup_kernel_stack), %g3 - st %g3, [%g6 + AOFF_task_kernel_stack_page] st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask] /* Compute NWINDOWS and stash it away. Now uses %wim trick explained diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c new file mode 100644 index 000000000..d0fc09346 --- /dev/null +++ b/arch/sparc/kernel/init_task.c @@ -0,0 +1,18 @@ +#include <linux/mm.h> +#include <linux/sched.h> + +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* .text section in head.S is aligned at 2 page boundry and this gets linked + * right after that so that the init_task_union is aligned properly as well. + * We really don't need this special alignment like the Intel does, but + * I do it anyways for completeness. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 70042857f..b22f008a1 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.72 1997/04/20 11:41:26 ecd Exp $ +/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -313,8 +313,180 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); +#ifdef DEBUG_IRQLOCK + +static unsigned long previous_irqholder; + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } + +static inline void wait_on_irq(int cpu, unsigned long where) +{ + int stuck = INIT_STUCK; + int local_count = local_irq_count[cpu]; + + /* Are we the only one in an interrupt context? */ + while (local_count != atomic_read(&global_irq_count)) { + /* + * No such luck. Now we need to release the lock, + * _and_ release our interrupt context, because + * otherwise we'd have dead-locks and live-locks + * and other fun things. + */ + atomic_sub(local_count, &global_irq_count); + spin_unlock(&global_irq_lock); + + /* + * Wait for everybody else to go away and release + * their things before trying to get the lock again. + */ + for (;;) { + STUCK; + if (atomic_read(&global_irq_count)) + continue; + if (*((unsigned char *)&global_irq_lock)) + continue; + if (spin_trylock(&global_irq_lock)) + break; + } + atomic_add(local_count, &global_irq_count); + } +} + +#undef INIT_STUCK +#define INIT_STUCK 10000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} + +static inline void get_irqlock(int cpu, unsigned long where) +{ + int stuck = INIT_STUCK; + + if (!spin_trylock(&global_irq_lock)) { + /* do we already hold the lock? */ + if ((unsigned char) cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait.. */ + do { + do { + STUCK; + barrier(); + } while (*((unsigned char *)&global_irq_lock)); + } while (!spin_trylock(&global_irq_lock)); + } + /* + * Ok, we got the lock bit. + * But that's actually just the easy part.. Now + * we need to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu, where); + + /* + * Finally. + */ + global_irq_holder = cpu; + previous_irqholder = where; +} + +void __global_cli(void) +{ + int cpu = smp_processor_id(); + unsigned long where; + + __asm__("mov %%i7, %0" : "=r" (where)); + __cli(); + get_irqlock(cpu, where); +} + +void __global_sti(void) +{ + release_irqlock(smp_processor_id()); + __sti(); +} + +unsigned long __global_save_flags(void) +{ + return global_irq_holder == (unsigned char) smp_processor_id(); +} + +void __global_restore_flags(unsigned long flags) +{ + if(flags & 1) { + __global_cli(); + } else { + /* release_irqlock() */ + if(global_irq_holder == smp_processor_id()) { + global_irq_holder = NO_PROC_ID; + spin_unlock(&global_irq_lock); + } + if(!(flags & 2)) + __sti(); + } +} + +#undef INIT_STUCK +#define INIT_STUCK 200000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} + +#define VERBOSE_IRQLOCK_DEBUGGING + +void irq_enter(int cpu, int irq, void *_opaque) +{ +#ifdef VERBOSE_IRQLOCK_DEBUGGING + extern void smp_show_backtrace_all_cpus(void); +#endif + int stuck = INIT_STUCK; + + hardirq_enter(cpu); + barrier(); + while (*((unsigned char *)&global_irq_lock)) { + if ((unsigned char) cpu == global_irq_holder) { + struct pt_regs *regs = _opaque; + int sbh_cnt = atomic_read(&__sparc_bh_counter); + int globl_locked = *((unsigned char *)&global_irq_lock); + int globl_icount = atomic_read(&global_irq_count); + int local_count = local_irq_count[cpu]; + unsigned long pc = regs->pc; + + /* It is very important that we load the state variables + * before we do the first call to printk() as printk() + * could end up changing them... + */ + + printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled " + "interrupt at PC[%08lx]\n", cpu, pc); + printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n", + cpu, sbh_cnt, globl_locked, globl_icount, local_count); +#ifdef VERBOSE_IRQLOCK_DEBUGGING + printk("Performing backtrace on all cpus, write this down!\n"); + smp_show_backtrace_all_cpus(); +#endif + break; + } + STUCK; + barrier(); + } +} + +void irq_exit(int cpu, int irq) +{ + hardirq_exit(cpu); + release_irqlock(cpu); +} + +#endif /* DEBUG_IRQLOCK */ + /* There has to be a better way. */ -/* XXX Must write faster version in irqlock.S -DaveM */ void synchronize_irq(void) { int cpu = smp_processor_id(); @@ -371,7 +543,7 @@ void handler_irq(int irq, struct pt_regs * regs) if(irq < 10) smp_irq_rotate(cpu); #endif - irq_enter(cpu, cpu_irq); + irq_enter(cpu, cpu_irq, regs); action = *(cpu_irq + irq_action); kstat.interrupts[cpu_irq]++; do { @@ -392,7 +564,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) int cpu = smp_processor_id(); disable_pil_irq(irq); - irq_enter(cpu, irq); + irq_enter(cpu, irq, regs); floppy_interrupt(irq, dev_id, regs); irq_exit(cpu, irq); enable_pil_irq(irq); diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 96c57e963..1adc9e817 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $ +/* $Id: process.c,v 1.98 1997/05/14 20:44:54 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -41,6 +41,8 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); +struct task_struct *current_set[NR_CPUS] = {&init_task, }; + #ifndef __SMP__ #define SUN4C_FAULT_HIGH 100 @@ -192,6 +194,37 @@ void show_regwindow(struct reg_window *rw) rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } +static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED; + +void show_backtrace(void) +{ + struct reg_window *rw; + unsigned long flags; + unsigned long fp; + int cpu = smp_processor_id(); + + spin_lock_irqsave(&sparc_backtrace_lock, flags); + __asm__ __volatile__("mov %%i6, %0" : "=r" (fp)); + rw = (struct reg_window *) fp; + while(rw) { + printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] " + "FP[%08lx] CALLER[%08lx]\n", cpu, + rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], + rw->ins[4], rw->ins[5], + rw->ins[6], + rw->ins[7]); + rw = (struct reg_window *) rw->ins[6]; + } + spin_unlock_irqrestore(&sparc_backtrace_lock, flags); +} + +#ifdef __SMP__ +void smp_show_backtrace_all_cpus(void) +{ + xc0((smpfunc_t) show_backtrace); +} +#endif + void show_stackframe(struct sparc_stackf *sf) { unsigned long size; @@ -441,12 +474,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, if(regs->psr & PSR_PS) stack_offset -= REGWIN_SZ; - childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); + childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset)); copy_regs(childregs, regs); new_stack = (((struct reg_window *) childregs) - 1); copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); - p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack; + p->tss.ksp = (unsigned long) new_stack; #ifdef __SMP__ p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8); p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL; @@ -467,7 +500,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; - if (sp != current->tss.kregs->u_regs[UREG_FP]) { + if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf *childstack; struct sparc_stackf *parentstack; @@ -475,9 +508,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, * This is a clone() call with supplied user stack. * Set some valid stack frames to give to the child. */ - childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *) - current->tss.kregs->u_regs[UREG_FP]; + childstack = (struct sparc_stackf *) sp; + parentstack = (struct sparc_stackf *) regs->u_regs[UREG_FP]; #if 0 printk("clone: parent stack:\n"); diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 647081eda..732b3006d 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -24,18 +24,6 @@ #define MAGIC_CONSTANT 0x80000000 -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * This routine gets a long from any process space by following the page * tables. NOTE! You should check that the long isn't on a page boundary, @@ -53,7 +41,7 @@ static unsigned long get_long(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -63,7 +51,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -73,7 +61,7 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(tsk, vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -106,7 +94,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -116,7 +104,7 @@ repeat: } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -126,12 +114,12 @@ repeat: } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 1); + handle_mm_fault(tsk, vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -533,7 +521,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } #endif - if(!(child = get_task(pid))) { + if(!(child = find_task_by_pid(pid))) { pt_error_return(regs, ESRCH); goto out; } diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index f2af0b763..aa204db06 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.83 1997/04/01 02:21:49 davem Exp $ +/* $Id: setup.c,v 1.84 1997/05/08 17:45:16 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -83,7 +83,8 @@ void prom_sync_me(void) #ifdef __SMP__ global_irq_holder = NO_PROC_ID; - global_irq_lock = global_bh_lock = 0; + *((unsigned char *)&global_irq_lock) = 0; + *((unsigned char *)&global_bh_lock) = 0; #endif __save_and_cli(flags); __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr)); diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 8a07ae0be..fd5fa634e 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.73 1997/04/16 05:56:05 davem Exp $ +/* $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -780,8 +780,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { + lock_kernel(); if(current->binfmt->core_dump(signr, regs)) signr |= 0x80; + unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 6622f88f0..beef2df14 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -4,16 +4,18 @@ */ #include <asm/head.h> -#include <asm/ptrace.h> -#include <asm/atomic.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/tasks.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <asm/ptrace.h> +#include <asm/atomic.h> + #include <asm/delay.h> #include <asm/irq.h> #include <asm/page.h> @@ -24,6 +26,9 @@ #include <asm/hardirq.h> #include <asm/softirq.h> +#define __KERNEL_SYSCALLS__ +#include <linux/unistd.h> + #define IRQ_RESCHEDULE 13 #define IRQ_STOP_CPU 14 #define IRQ_CROSS_CALL 15 @@ -33,6 +38,9 @@ extern int linux_num_cpus; extern void calibrate_delay(void); +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + volatile int smp_processors_ready = 0; unsigned long cpu_present_map = 0; @@ -118,16 +126,6 @@ void smp_store_cpu_info(int id) cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */ } -/* - * Architecture specific routine called by the kernel just before init is - * fired off. This allows the BP to have everything in order [we hope]. - * At the end of this all the AP's will hit the system scheduling and off - * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over - * and give them jobs to do. smp_callin is a standard routine - * we use to track CPU's as they power up. - */ - void smp_commence(void) { /* @@ -144,7 +142,7 @@ static void smp_setup_percpu_timer(void); void smp_callin(void) { - int cpuid = smp_processor_id(); + int cpuid = hard_smp_processor_id(); local_flush_cache_all(); local_flush_tlb_all(); @@ -183,6 +181,25 @@ void smp_callin(void) __sti(); } +extern int cpu_idle(void *unused); +extern void init_IRQ(void); + +/* Only broken Intel needs this, thus it should not even be referenced + * globally... + */ +void initialize_secondary(void) +{ +} + +/* Activate a secondary processor. */ +int start_secondary(void *unused) +{ + trap_init(); + init_IRQ(); + smp_callin(); + return cpu_idle(NULL); +} + void cpu_panic(void) { printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id()); @@ -220,6 +237,7 @@ void smp_boot_cpus(void) cpu_number_map[boot_cpu_id] = 0; cpu_logical_map[0] = boot_cpu_id; klock_info.akp = boot_cpu_id; + current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); set_irq_udt(mid_xlate[boot_cpu_id]); smp_setup_percpu_timer(); @@ -233,10 +251,19 @@ void smp_boot_cpus(void) if(cpu_present_map & (1 << i)) { extern unsigned long sparc_cpu_startup; unsigned long *entry = &sparc_cpu_startup; + struct task_struct *p; int timeout; + /* Cook up an idler for this guy. */ + kernel_thread(start_secondary, NULL, CLONE_PID); + + p = task[++cpucount]; + + p->processor = i; + current_set[i] = p; + /* See trampoline.S for details... */ - entry += ((i-1) * 6); + entry += ((i-1) * 3); /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); @@ -253,10 +280,10 @@ void smp_boot_cpus(void) } if(cpu_callin_map[i]) { /* Another "Red Snapper". */ - cpucount++; cpu_number_map[i] = i; cpu_logical_map[i] = i; } else { + cpucount--; printk("Processor %d is stuck.\n", i); } } @@ -364,26 +391,17 @@ struct smp_funcall { unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */ } ccall_info; -/* Returns failure code if for example any of the cpu's failed to respond - * within a certain timeout period. - */ - -#define CCALL_TIMEOUT 5000000 /* enough for initial testing */ - static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED; /* Cross calls must be serialized, at least currently. */ void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - unsigned long me = smp_processor_id(); - unsigned long flags, mask; - int i, timeout; - if(smp_processors_ready) { - __save_flags(flags); - __cli(); - spin_lock(&cross_call_lock); + register int ncpus = smp_num_cpus; + unsigned long flags; + + spin_lock_irqsave(&cross_call_lock, flags); /* Init function glue. */ ccall_info.func = func; @@ -393,56 +411,47 @@ void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, ccall_info.arg4 = arg4; ccall_info.arg5 = arg5; - /* Init receive/complete mapping. */ - for(i = 0; i < smp_num_cpus; i++) { - ccall_info.processors_in[i] = 0; - ccall_info.processors_out[i] = 0; + /* Init receive/complete mapping, plus fire the IPI's off. */ + { + register void (*send_ipi)(int,int) = set_cpu_int; + register unsigned long mask; + register int i; + + mask = (cpu_present_map & ~(1 << smp_processor_id())); + for(i = 0; i < ncpus; i++) { + if(mask & (1 << i)) { + ccall_info.processors_in[i] = 0; + ccall_info.processors_out[i] = 0; + send_ipi(mid_xlate[i], IRQ_CROSS_CALL); + } else { + ccall_info.processors_in[i] = 1; + ccall_info.processors_out[i] = 1; + } + } } - ccall_info.processors_in[me] = 1; - ccall_info.processors_out[me] = 1; - /* Fire it off. */ - mask = (cpu_present_map & ~(1 << me)); - for(i = 0; i < 4; i++) { - if(mask & (1 << i)) - set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL); - } + /* First, run local copy. */ + func(arg1, arg2, arg3, arg4, arg5); - /* For debugging purposes right now we can timeout - * on both callin and callexit. - */ - timeout = CCALL_TIMEOUT; - for(i = 0; i < smp_num_cpus; i++) { - while(!ccall_info.processors_in[i] && timeout-- > 0) - barrier(); - if(!ccall_info.processors_in[i]) - goto procs_time_out; - } + { + register int i; - /* Run local copy. */ - func(arg1, arg2, arg3, arg4, arg5); + i = 0; + do { + while(!ccall_info.processors_in[i]) + barrier(); + } while(++i < ncpus); - /* Spin on proc dispersion. */ - timeout = CCALL_TIMEOUT; - for(i = 0; i < smp_num_cpus; i++) { - while(!ccall_info.processors_out[i] && timeout-- > 0) - barrier(); - if(!ccall_info.processors_out[i]) - goto procs_time_out; + i = 0; + do { + while(!ccall_info.processors_out[i]) + barrier(); + } while(++i < ncpus); } - spin_unlock(&cross_call_lock); - __restore_flags(flags); - return; /* made it... */ - -procs_time_out: - printk("smp: Wheee, penguin drops off the bus\n"); - spin_unlock(&cross_call_lock); - __restore_flags(flags); - return; /* why me... why me... */ - } - /* Just need to run local copy. */ - func(arg1, arg2, arg3, arg4, arg5); + spin_unlock_irqrestore(&cross_call_lock, flags); + } else + func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */ } void smp_flush_cache_all(void) @@ -453,43 +462,98 @@ void smp_flush_tlb_all(void) void smp_flush_cache_mm(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT) - xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm); + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_cache_mm(mm); + else + xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm); + } } void smp_flush_tlb_mm(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT) - xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm); + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) { + local_flush_tlb_mm(mm); + } else { + xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm); + if(mm->count == 1 && current->mm == mm) + mm->cpu_vm_mask = (1 << smp_processor_id()); + } + } } void smp_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - if(mm->context != NO_CONTEXT) - xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm, - start, end); + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_cache_range(mm, start, end); + else + xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm, + start, end); + } } void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - if(mm->context != NO_CONTEXT) - xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm, - start, end); + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_tlb_range(mm, start, end); + else + xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm, + start, end); + } } void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page) -{ xc2((smpfunc_t) local_flush_cache_page, (unsigned long) vma, page); } +{ + struct mm_struct *mm = vma->vm_mm; + + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_cache_page(vma, page); + else + xc2((smpfunc_t) local_flush_cache_page, + (unsigned long) vma, page); + } +} void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page); } +{ + struct mm_struct *mm = vma->vm_mm; + + if(mm->context != NO_CONTEXT) { + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_tlb_page(vma, page); + else + xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page); + } +} void smp_flush_page_to_ram(unsigned long page) -{ xc1((smpfunc_t) local_flush_page_to_ram, page); } +{ + /* Current theory is that those who call this are the one's + * who have just dirtied their cache with the pages contents + * in kernel space, therefore we only run this on local cpu. + * + * XXX This experiment failed, research further... -DaveM + */ +#if 1 + xc1((smpfunc_t) local_flush_page_to_ram, page); +#else + local_flush_page_to_ram(page); +#endif +} void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) -{ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr); } +{ + if(mm->cpu_vm_mask == (1 << smp_processor_id())) + local_flush_sig_insns(mm, insn_addr); + else + xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr); +} /* Reschedule call back. */ void smp_reschedule_irq(void) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 645aafb35..38896ab22 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.56 1997/04/18 05:44:35 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.59 1997/05/08 17:45:20 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -38,6 +38,7 @@ #include <asm/dma.h> #endif #include <asm/a.out.h> +#include <asm/spinlock.h> struct poll { int fd; @@ -50,9 +51,9 @@ extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); -extern void __copy_1page(void *, const void *); +extern void (*__copy_1page)(void *, const void *); extern void __memmove(void *, const void *, __kernel_size_t); -extern void *bzero_1page(void *); +extern void (*bzero_1page)(void *); extern void *__bzero(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); @@ -87,17 +88,47 @@ EXPORT_SYMBOL(klock_info); EXPORT_SYMBOL_PRIVATE(_lock_kernel); EXPORT_SYMBOL_PRIVATE(_unlock_kernel); EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); +#ifdef SPIN_LOCK_DEBUG +EXPORT_SYMBOL(_spin_lock); +EXPORT_SYMBOL(_spin_unlock); +EXPORT_SYMBOL(_spin_trylock); +EXPORT_SYMBOL(_spin_lock_irq); +EXPORT_SYMBOL(_spin_unlock_irq); +EXPORT_SYMBOL(_spin_lock_irqsave); +EXPORT_SYMBOL(_spin_unlock_irqrestore); +EXPORT_SYMBOL(_read_lock); +EXPORT_SYMBOL(_read_unlock); +EXPORT_SYMBOL(_read_lock_irq); +EXPORT_SYMBOL(_read_unlock_irq); +EXPORT_SYMBOL(_read_lock_irqsave); +EXPORT_SYMBOL(_read_unlock_irqrestore); +EXPORT_SYMBOL(_write_lock); +EXPORT_SYMBOL(_write_unlock); +EXPORT_SYMBOL(_write_lock_irq); +EXPORT_SYMBOL(_write_unlock_irq); +EXPORT_SYMBOL(_write_lock_irqsave); +EXPORT_SYMBOL(_write_unlock_irqrestore); +#else EXPORT_SYMBOL_PRIVATE(_rw_read_enter); EXPORT_SYMBOL_PRIVATE(_rw_read_exit); EXPORT_SYMBOL_PRIVATE(_rw_write_enter); +#endif EXPORT_SYMBOL(__sparc_bh_counter); #ifdef __SMP__ +#ifdef DEBUG_IRQLOCK +EXPORT_SYMBOL(irq_enter); +EXPORT_SYMBOL(irq_exit); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_cli); +#else EXPORT_SYMBOL_PRIVATE(_irq_enter); EXPORT_SYMBOL_PRIVATE(_irq_exit); EXPORT_SYMBOL_PRIVATE(_global_restore_flags); EXPORT_SYMBOL_PRIVATE(_global_sti); EXPORT_SYMBOL_PRIVATE(_global_cli); #endif +#endif EXPORT_SYMBOL(page_offset); EXPORT_SYMBOL(stack_top); diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 5f5b19504..3fafe7f9c 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.78 1997/04/16 05:56:12 davem Exp $ +/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,7 @@ #include <linux/resource.h> #include <linux/ipc.h> #include <linux/shm.h> +#include <linux/msg.h> #include <linux/sem.h> #include <linux/signal.h> #include <linux/uio.h> @@ -1031,7 +1032,48 @@ asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, unlock_kernel(); return ret; } - + +extern asmlinkage int sys_msgget (key_t key, int msgflg); +extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, + size_t msgsz, long msgtyp, int msgflg); +extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, + size_t msgsz, int msgflg); +extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); + +asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + struct sparc_stackf *sp; + unsigned long arg5; + int rval; + + lock_kernel(); + switch(op) { + case 0: + rval = sys_msgget((key_t)arg1, (int)arg2); + break; + case 1: + rval = sys_msgctl((int)arg1, (int)arg2, + (struct msqid_ds *)arg3); + break; + case 2: + sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP]; + arg5 = sp->xxargs[0]; + rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2, + (size_t)arg3, (long)arg4, (int)arg5); + break; + case 3: + rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2, + (size_t)arg3, (int)arg4); + break; + default: + rval = -EINVAL; + break; + } + unlock_kernel(); + return rval; +} + extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); extern asmlinkage int sys_shmdt (char *shmaddr); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 61b41056b..a166e3490 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.60 1997/04/19 08:52:15 jj Exp $ +/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -106,15 +106,26 @@ C_LABEL(sys_call_table): .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek) /* "We are the Knights of the Forest of Ni!!" */ - .long C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall) - .long C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam) - .long C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min) - .long C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep) + .long C_LABEL(sys_mlock) + .long C_LABEL(sys_munlock) + .long C_LABEL(sys_mlockall) +/*240*/ .long C_LABEL(sys_munlockall) + .long C_LABEL(sys_sched_setparam) + .long C_LABEL(sys_sched_getparam) + .long C_LABEL(sys_sched_setscheduler) + .long C_LABEL(sys_sched_getscheduler) +/*245*/ .long C_LABEL(sys_sched_yield) + .long C_LABEL(sys_sched_get_priority_max) + .long C_LABEL(sys_sched_get_priority_min) + .long C_LABEL(sys_sched_rr_get_interval) + .long C_LABEL(sys_nanosleep) /*250*/ .long C_LABEL(sys_mremap) .long C_LABEL(sys_sysctl) - .long C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nfsservctl) - .long C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_getsid) + .long C_LABEL(sys_fdatasync) + .long C_LABEL(sys_nfsservctl) +/*255*/ .long C_LABEL(sys_aplib) + .long C_LABEL(sys_nis_syscall) /* Now the SunOS syscall table. */ @@ -179,7 +190,7 @@ C_LABEL(sunos_sys_table): .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname) .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys) .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) + .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid) .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c index bea6336c5..03fe3cff9 100644 --- a/arch/sparc/kernel/tadpole.c +++ b/arch/sparc/kernel/tadpole.c @@ -4,6 +4,8 @@ */ #include <linux/string.h> +#include <linux/kernel.h> +#include <linux/sched.h> #include <asm/asi.h> #include <asm/oplib.h> diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S index c59a2531a..9ee5bd14a 100644 --- a/arch/sparc/kernel/trampoline.S +++ b/arch/sparc/kernel/trampoline.S @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $ +/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $ * trampoline.S: SMP cpu boot-up trampoline code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ #include <asm/cprefix.h> #include <asm/head.h> #include <asm/psr.h> +#include <asm/page.h> #include <asm/asi.h> #include <asm/ptrace.h> #include <asm/vaddrs.h> @@ -25,27 +26,18 @@ C_LABEL(sparc_cpu_startup): cpu1_startup: sethi %hi(C_LABEL(trapbase_cpu1)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3 - sethi %hi(C_LABEL(cpu1_stack)), %g2 - or %g2, %lo(C_LABEL(cpu1_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3 cpu2_startup: sethi %hi(C_LABEL(trapbase_cpu2)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3 - sethi %hi(C_LABEL(cpu2_stack)), %g2 - or %g2, %lo(C_LABEL(cpu2_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3 cpu3_startup: sethi %hi(C_LABEL(trapbase_cpu3)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3 - sethi %hi(C_LABEL(cpu3_stack)), %g2 - or %g2, %lo(C_LABEL(cpu3_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3 1: /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */ @@ -62,14 +54,16 @@ cpu3_startup: wr %g3, 0x0, %tbr WRITE_PAUSE - /* Give ourselves a stack. */ - set 0x2000, %g5 - add %g2, %g5, %g2 ! end of stack - sub %g2, REGWIN_SZ, %sp - mov 0, %fp + /* Give ourselves a stack and curptr. */ + set C_LABEL(current_set), %g5 + srl %g3, 10, %g4 + and %g4, 0xc, %g4 + ld [%g5 + %g4], %g6 - /* Set up curptr. */ - set C_LABEL(init_task), %g6 + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, REGWIN_SZ, %sp + add %g6, %sp, %sp /* Turn on traps (PSR_ET). */ rd %psr, %g1 diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S index bad0088f4..890676bfb 100644 --- a/arch/sparc/kernel/wof.S +++ b/arch/sparc/kernel/wof.S @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $ +/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -234,15 +234,20 @@ spwin_user_stack_is_bolixed: spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] - /* Jump onto kernel stack for this process... */ - ld [%curptr + AOFF_task_saved_kernel_stack], %sp + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp + add %curptr, %sp, %sp /* Restore the saved globals and build a pt_regs frame. */ mov %saved_g5, %g5 - mov %g6, %l4 mov %saved_g6, %g6 STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1) - mov %l4, %g6 + + mov 1, %g6 + sll %g6, (PAGE_SHIFT + 1), %g6 + sub %g6, (TRACEREG_SZ + REGWIN_SZ), %g6 + sub %sp, %g6, %g6 /* Turn on traps and call c-code to deal with it. */ wr %t_psr, PSR_ET, %psr diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S index 7550dd627..cb407aa69 100644 --- a/arch/sparc/kernel/wuf.S +++ b/arch/sparc/kernel/wuf.S @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $ +/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -145,14 +145,17 @@ fwin_user_stack_is_bolixed: * to the trap window and call c-code to deal with this. */ LOAD_CURRENT(l4, l5) - ld [%l4 + AOFF_task_saved_kernel_stack], %l5 + + mov 1, %l5 + sll %l5, (PAGE_SHIFT + 1), %l5 + sub %l5, (TRACEREG_SZ + REGWIN_SZ), %l5 + add %l4, %l5, %l5 /* Store globals into pt_regs frame. */ STORE_PT_GLOBALS(l5) STORE_PT_YREG(l5, g3) - /* Save kernel %sp in global while we change windows. */ - mov %l5, %g2 + /* Save current in a global while we change windows. */ mov %l4, %curptr save %g0, %g0, %g0 @@ -166,7 +169,10 @@ fwin_user_stack_is_bolixed: /* LOCATION: Window 'T' */ - mov %g2, %sp /* Jump onto kernel %sp being held */ + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp + add %curptr, %sp, %sp /* Build rest of pt_regs. */ STORE_PT_INS(sp) diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 1bf49bf13..cefe7a851 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -1,13 +1,11 @@ -# $Id: Makefile,v 1.23 1997/04/18 05:44:39 davem Exp $ +# $Id: Makefile,v 1.24 1997/05/08 17:45:26 davem Exp $ # Makefile for Sparc library files.. # -CFLAGS := $(CFLAGS) -ansi - OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ - copy_user.o locks.o atomic.o bitops.o + copy_user.o locks.o atomic.o bitops.o debuglocks.o ifdef SMP OBJS += irqlock.o diff --git a/arch/sparc/lib/blockops.S b/arch/sparc/lib/blockops.S index f8a9e80df..c11ab1b20 100644 --- a/arch/sparc/lib/blockops.S +++ b/arch/sparc/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.5 1996/09/24 05:22:56 davem Exp $ +/* $Id: blockops.S,v 1.6 1997/05/03 02:01:54 davem Exp $ * blockops.S: Common block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -46,25 +46,7 @@ .text .align 4 - .globl C_LABEL(bzero_2page), C_LABEL(bzero_1page) -C_LABEL(bzero_2page): - /* %o0 = buf */ - or %g0, %g0, %g1 - or %o0, %g0, %o1 - or %g0, 0x20, %g2 -1: - BLAST_BLOCK(%o0, 0x00) - BLAST_BLOCK(%o0, 0x40) - BLAST_BLOCK(%o0, 0x80) - BLAST_BLOCK(%o0, 0xc0) - subcc %g2, 1, %g2 - bne 1b - add %o0, 0x100, %o0 - - retl - mov %o1, %o0 - -C_LABEL(bzero_1page): +generic_bzero_1page: /* %o0 = buf */ or %g0, %g0, %g1 or %o0, %g0, %o1 @@ -79,10 +61,9 @@ C_LABEL(bzero_1page): add %o0, 0x100, %o0 retl - mov %o1, %o0 + nop - .globl C_LABEL(__copy_1page) -C_LABEL(__copy_1page): +__generic_copy_1page: /* %o0 = dst, %o1 = src */ or %g0, 0x10, %g1 1: @@ -101,3 +82,9 @@ C_LABEL(__copy_1page): retl nop + + .data + .align 4 + .globl C_LABEL(bzero_1page), C_LABEL(__copy_1page) +C_LABEL(bzero_1page): .word generic_bzero_1page +C_LABEL(__copy_1page): .word __generic_copy_1page diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c new file mode 100644 index 000000000..006cba5a8 --- /dev/null +++ b/arch/sparc/lib/debuglocks.c @@ -0,0 +1,463 @@ +/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $ + * debuglocks.c: Debugging versions of SMP locking primitives. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/psr.h> +#include <asm/system.h> +#include <asm/spinlock.h> + +/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */ +#ifdef SPIN_LOCK_DEBUG + +/* Some notes on how these debugging routines work. When a lock is acquired + * an extra debugging member lock->owner_pc is set to the caller of the lock + * acquisition routine. Right before releasing a lock, the debugging program + * counter is cleared to zero. + * + * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU + * number of the owner in the lowest two bits. + */ + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } + +void _spin_lock(spinlock_t *lock) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +again: + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(val) { + while(lock->lock) { + STUCK; + barrier(); + } + goto again; + } + lock->owner_pc = (cpu & 3) | (caller & ~3); +} + +int _spin_trylock(spinlock_t *lock) +{ + unsigned long val; + unsigned long caller; + int cpu = smp_processor_id(); + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(!val) { + /* We got it, record our identity for debugging. */ + lock->owner_pc = (cpu & 3) | (caller & ~3); + } + return val == 0; +} + +void _spin_unlock(spinlock_t *lock) +{ + lock->owner_pc = 0; + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } + +void _spin_lock_irq(spinlock_t *lock) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __cli(); + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +again: + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(val) { + while(lock->lock) { + STUCK; + barrier(); + } + goto again; + } + lock->owner_pc = (cpu & 3) | (caller & ~3); +} + +void _spin_unlock_irq(spinlock_t *lock) +{ + lock->owner_pc = 0; + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); + __sti(); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } + +/* Caller macro does __save_and_cli(flags) for us. */ +void _spin_lock_irqsave(spinlock_t *lock) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +again: + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(val) { + while(lock->lock) { + STUCK; + barrier(); + } + goto again; + } + lock->owner_pc = (cpu & 3) | (caller & ~3); +} + +void _spin_unlock_irqrestore(spinlock_t *lock) +{ + lock->owner_pc = 0; + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _read_lock(rwlock_t *rw) +{ + unsigned long flags; + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __save_and_cli(flags); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))++; + barrier(); + (*(((unsigned short *)&rw->lock)+1)) = 0; + __restore_flags(flags); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _read_unlock(rwlock_t *rw) +{ + unsigned long flags, val, caller; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __save_and_cli(flags); +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))--; + barrier(); + (*(((unsigned char *)&rw->lock)+2))=0; + __restore_flags(flags); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _write_lock(rwlock_t *rw) +{ + unsigned long flags, val, caller; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __save_and_cli(flags); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } + rw->owner_pc = (cpu & 3) | (caller & ~3); + while(rw->lock & ~0xff) { + STUCK; + barrier(); + } +} + +void _write_unlock(rwlock_t *rw) +{ + rw->owner_pc = 0; + barrier(); + rw->lock = 0; +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _read_lock_irq(rwlock_t *rw) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __cli(); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))++; + barrier(); + (*(((unsigned short *)&rw->lock)+1)) = 0; +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _read_unlock_irq(rwlock_t *rw) +{ + unsigned long val, caller; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))--; + barrier(); + (*(((unsigned char *)&rw->lock)+2))=0; + __sti(); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _write_lock_irq(rwlock_t *rw) +{ + unsigned long val, caller; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + __cli(); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } + rw->owner_pc = (cpu & 3) | (caller & ~3); + while(rw->lock & ~0xff) { + STUCK; + barrier(); + } +} + +void _write_unlock_irq(rwlock_t *rw) +{ + rw->owner_pc = 0; + barrier(); + rw->lock = 0; + __sti(); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +/* Caller does __save_and_cli(flags) for us. */ +void _read_lock_irqsave(rwlock_t *rw) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))++; + barrier(); + (*(((unsigned short *)&rw->lock)+1)) = 0; +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +void _read_unlock_irqrestore(rwlock_t *rw) +{ + unsigned long val, caller; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +clock_again: + __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff00) { + STUCK; + barrier(); + } + goto clock_again; + } + (*((unsigned short *)&rw->lock))--; + barrier(); + (*(((unsigned char *)&rw->lock)+2))=0; +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + +/* Caller does __save_and_cli(flags) for us. */ +void _write_lock_irqsave(rwlock_t *rw) +{ + unsigned long val, caller; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + STUCK; + barrier(); + } + goto wlock_again; + } + rw->owner_pc = (cpu & 3) | (caller & ~3); + while(rw->lock & ~0xff) { + STUCK; + barrier(); + } +} + +void _write_unlock_irqrestore(rwlock_t *rw) +{ + rw->owner_pc = 0; + barrier(); + rw->lock = 0; +} + +#endif /* SPIN_LOCK_DEBUG */ diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S index db7dd26c3..23194e723 100644 --- a/arch/sparc/lib/irqlock.S +++ b/arch/sparc/lib/irqlock.S @@ -1,4 +1,4 @@ -/* $Id: irqlock.S,v 1.2 1997/04/19 04:33:37 davem Exp $ +/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $ * irqlock.S: High performance IRQ global locking and interrupt entry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 4ae57f18f..f7b9b367c 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.24 1997/04/20 14:11:49 ecd Exp $ +# $Id: Makefile,v 1.25 1997/05/03 05:09:11 davem Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -9,12 +9,30 @@ O_TARGET := mm.o O_OBJS := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \ - loadmmu.o generic.o asyncd.o extable.o + tsunami.o loadmmu.o generic.o asyncd.o extable.o include $(TOPDIR)/Rules.make +ifdef SMP + +hypersparc.o: hypersparc.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S + +viking.o: viking.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S + +tsunami.o: tsunami.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S + +else + hypersparc.o: hypersparc.S $(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S viking.o: viking.S $(CC) -D__ASSEMBLY__ -ansi -c -o viking.o viking.S + +tsunami.o: tsunami.S + $(CC) -D__ASSEMBLY__ -ansi -c -o tsunami.o tsunami.S + +endif diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c index 5d9d476a5..46635db97 100644 --- a/arch/sparc/mm/asyncd.c +++ b/arch/sparc/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.9 1996/12/18 06:43:22 tridge Exp $ +/* $Id: asyncd.c,v 1.10 1997/05/15 21:14:24 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -153,7 +153,7 @@ static int fault_in_page(int taskid, if(!pte) goto no_memory; if(!pte_present(*pte)) { - do_no_page(tsk, vma, address, write); + handle_mm_fault(tsk, vma, address, write); goto finish_up; } set_pte(pte, pte_mkyoung(*pte)); @@ -165,12 +165,11 @@ static int fault_in_page(int taskid, flush_tlb_page(vma, address); goto finish_up; } - do_wp_page(tsk, vma, address, write); + handle_mm_fault(tsk, vma, address, write); /* Fall through for do_wp_page */ finish_up: stats.success++; - update_mmu_cache(vma, address, *pte); return 0; no_memory: diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index cfac6bcc2..0d6490860 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.91 1997/03/18 17:56:00 jj Exp $ +/* $Id: fault.c,v 1.92 1997/05/15 21:14:21 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -229,7 +229,7 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(vma, address, write); + handle_mm_fault(current, vma, address, write); up(&mm->mmap_sem); goto out; /* @@ -370,7 +370,7 @@ good_area: else if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; - handle_mm_fault(vma, address, write); + handle_mm_fault(current, vma, address, write); up(&mm->mmap_sem); return; bad_area: diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S index 4e5a19301..62e2022e0 100644 --- a/arch/sparc/mm/hypersparc.S +++ b/arch/sparc/mm/hypersparc.S @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.4 1997/04/19 04:33:39 davem Exp $ +/* $Id: hypersparc.S,v 1.7 1997/05/03 05:09:12 davem Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -79,7 +79,7 @@ hypersparc_flush_cache_mm: sta %g0, [%o0 + %o4] ASI_M_FLUSH_USER hypersparc_flush_cache_mm_out: retl - sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE ! hyper_flush_whole_icache + nop /* The things we do for performance... */ hypersparc_flush_cache_range: @@ -126,7 +126,7 @@ hypersparc_flush_cache_range: bne 1b sta %g0, [%o3 + %g5] ASI_M_FLUSH_USER retl - sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE + nop /* Below our threshold, flush one page at a time. */ 0: @@ -166,7 +166,7 @@ hypersparc_flush_cache_range: sta %o3, [%g7] ASI_M_MMUREGS hypersparc_flush_cache_range_out: retl - sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE + nop /* HyperSparc requires a valid mapping where we are about to flush * in order to check for a physical tag match during the flush. @@ -221,12 +221,12 @@ hypersparc_flush_cache_page: sta %o2, [%g4] ASI_M_MMUREGS hypersparc_flush_cache_page_out: retl - sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE + nop hypersparc_flush_sig_insns: - flush %o2 + flush %o1 retl - flush %o2 + 4 + flush %o1 + 4 /* HyperSparc is copy-back. */ hypersparc_flush_page_to_ram: @@ -289,7 +289,7 @@ hypersparc_flush_tlb_mm: cmp %o1, -1 be hypersparc_flush_tlb_mm_out #endif - mov 0x300, %g2 + mov 0x300, %g2 sta %o1, [%g1] ASI_M_MMUREGS sta %g0, [%g2] ASI_M_FLUSH_PROBE hypersparc_flush_tlb_mm_out: @@ -304,7 +304,7 @@ hypersparc_flush_tlb_range: cmp %o3, -1 be hypersparc_flush_tlb_range_out #endif - srl %o1, SRMMU_PGDIR_SHIFT, %o1 + srl %o1, SRMMU_PGDIR_SHIFT, %o1 sta %o3, [%g1] ASI_M_MMUREGS sll %o1, SRMMU_PGDIR_SHIFT, %o1 sethi %hi(1 << SRMMU_PGDIR_SHIFT), %o4 @@ -324,13 +324,67 @@ hypersparc_flush_tlb_page: mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o3 andn %o1, (PAGE_SIZE - 1), %o1 - lda [%g1] ASI_M_MMUREGS, %g5 #ifndef __SMP__ cmp %o3, -1 be hypersparc_flush_tlb_page_out #endif + lda [%g1] ASI_M_MMUREGS, %g5 sta %o3, [%g1] ASI_M_MMUREGS sta %g0, [%o1] ASI_M_FLUSH_PROBE hypersparc_flush_tlb_page_out: retl sta %g5, [%g1] ASI_M_MMUREGS + + /* High speed page clear/copy. */ + .globl hypersparc_bzero_1page, hypersparc_copy_1page +hypersparc_bzero_1page: + clr %g1 + mov 32, %g2 + add %g2, %g2, %g3 + add %g2, %g3, %g4 + add %g2, %g4, %g5 + add %g2, %g5, %g7 + add %g2, %g7, %o2 + add %g2, %o2, %o3 + mov 16, %o1 +1: + stda %g0, [%o0 + %g0] ASI_M_BFILL + stda %g0, [%o0 + %g2] ASI_M_BFILL + stda %g0, [%o0 + %g3] ASI_M_BFILL + stda %g0, [%o0 + %g4] ASI_M_BFILL + stda %g0, [%o0 + %g5] ASI_M_BFILL + stda %g0, [%o0 + %g7] ASI_M_BFILL + stda %g0, [%o0 + %o2] ASI_M_BFILL + stda %g0, [%o0 + %o3] ASI_M_BFILL + subcc %o1, 1, %o1 + bne 1b + add %o0, 256, %o0 + + retl + nop + +hypersparc_copy_1page: + sub %o1, %o0, %o2 ! difference + mov 16, %g1 +1: + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + add %o0, 32, %o0 + sta %o0, [%o0 + %o2] ASI_M_BCOPY + subcc %g1, 1, %g1 + bne 1b + add %o0, 32, %o0 + + retl + nop diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 9d3afdbdf..b04064efb 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.136 1997/04/20 14:11:51 ecd Exp $ +/* $Id: srmmu.c,v 1.146 1997/05/18 21:11:09 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -77,12 +77,20 @@ ctxd_t *srmmu_context_table; /* Don't change this without changing access to this * in arch/sparc/mm/viking.S */ -struct srmmu_trans { +static struct srmmu_trans { unsigned long vbase; unsigned long pbase; unsigned long size; } srmmu_map[SPARC_PHYS_BANKS]; +#define SRMMU_HASHSZ 256 + +/* Not static, viking.S uses it. */ +struct srmmu_trans *srmmu_v2p_hash[SRMMU_HASHSZ]; +static struct srmmu_trans *srmmu_p2v_hash[SRMMU_HASHSZ]; + +#define srmmu_ahashfn(addr) ((addr) >> 24) + static int viking_mxcc_present = 0; void srmmu_frob_mem_map(unsigned long start_mem) @@ -113,31 +121,26 @@ void srmmu_frob_mem_map(unsigned long start_mem) /* Physical memory can be _very_ non-contiguous on the sun4m, especially * the SS10/20 class machines and with the latest openprom revisions. - * So we have to crunch the free page pool. + * So we have to do a quick lookup. */ static inline unsigned long srmmu_v2p(unsigned long vaddr) { - int i; + struct srmmu_trans *tp = srmmu_v2p_hash[srmmu_ahashfn(vaddr)]; - for(i=0; srmmu_map[i].size != 0; i++) { - if(srmmu_map[i].vbase <= vaddr && - (srmmu_map[i].vbase + srmmu_map[i].size > vaddr)) { - return (vaddr - srmmu_map[i].vbase) + srmmu_map[i].pbase; - } - } - return 0xffffffffUL; + if(tp) + return (vaddr - tp->vbase + tp->pbase); + else + return 0xffffffffUL; } static inline unsigned long srmmu_p2v(unsigned long paddr) { - int i; + struct srmmu_trans *tp = srmmu_p2v_hash[srmmu_ahashfn(paddr)]; - for(i=0; srmmu_map[i].size != 0; i++) { - if(srmmu_map[i].pbase <= paddr && - (srmmu_map[i].pbase + srmmu_map[i].size > paddr)) - return (paddr - srmmu_map[i].pbase) + srmmu_map[i].vbase; - } - return 0xffffffffUL; + if(tp) + return (paddr - tp->pbase + tp->vbase); + else + return 0xffffffffUL; } /* In general all page table modifications should use the V8 atomic @@ -659,27 +662,6 @@ static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval) srmmu_set_entry(ptep, pte_val(pteval)); } -static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) -{ - unsigned long page = ((unsigned long)ptep) & PAGE_MASK; - - srmmu_set_entry(ptep, pte_val(pteval)); - __asm__ __volatile__(" - lda [%0] %2, %%g4 - orcc %%g4, 0x0, %%g0 - be 2f - sethi %%hi(%7), %%g5 -1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page - bne 1b - sta %%g0, [%1 + %%g5] %3 - lda [%4] %5, %%g0 -2:" : /* no outputs */ - : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), - "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5", "cc"); -} - static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval) { register unsigned long a, b, c, d, e, f, g; @@ -860,134 +842,27 @@ static void srmmu_unlockarea(char *vaddr, unsigned long len) */ struct task_struct *srmmu_alloc_task_struct(void) { - return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL); -} - -unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk) -{ - unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0); - - if(!kstk) - kstk = (unsigned long) vmalloc(PAGE_SIZE << 1); - - return kstk; + return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0); } static void srmmu_free_task_struct(struct task_struct *tsk) { - kfree(tsk); -} - -static void srmmu_free_kernel_stack(unsigned long stack) -{ - if(stack < VMALLOC_START) - free_pages(stack, 1); - else - vfree((char *)stack); -} - -/* Tsunami flushes. It's page level tlb invalidation is not very - * useful at all, you must be in the context that page exists in to - * get a match. - */ -static void tsunami_flush_cache_all(void) -{ - flush_user_windows(); - tsunami_flush_icache(); - tsunami_flush_dcache(); -} - -static void tsunami_flush_cache_mm(struct mm_struct *mm) -{ - FLUSH_BEGIN(mm) - flush_user_windows(); - tsunami_flush_icache(); - tsunami_flush_dcache(); - FLUSH_END -} - -static void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) -{ - FLUSH_BEGIN(mm) - flush_user_windows(); - tsunami_flush_icache(); - tsunami_flush_dcache(); - FLUSH_END -} - -static void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page) -{ - FLUSH_BEGIN(vma->vm_mm) - flush_user_windows(); - tsunami_flush_icache(); - tsunami_flush_dcache(); - FLUSH_END -} - -/* Tsunami does not have a Copy-back style virtual cache. */ -static void tsunami_flush_page_to_ram(unsigned long page) -{ -} - -/* However, Tsunami is not IO coherent. */ -static void tsunami_flush_page_for_dma(unsigned long page) -{ - tsunami_flush_icache(); - tsunami_flush_dcache(); -} - -/* Tsunami has harvard style split I/D caches which do not snoop each other, - * so we have to flush on-stack sig insns. Only the icache need be flushed - * since the Tsunami has a write-through data cache. - */ -static void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) -{ - tsunami_flush_icache(); -} - -static void tsunami_flush_chunk(unsigned long chunk) -{ + free_pages((unsigned long)tsk, 1); } -static void tsunami_flush_tlb_all(void) -{ - srmmu_flush_whole_tlb(); - module_stats.invall++; -} - -static void tsunami_flush_tlb_mm(struct mm_struct *mm) -{ - FLUSH_BEGIN(mm) - srmmu_flush_whole_tlb(); - module_stats.invmm++; - FLUSH_END -} - -static void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) -{ - FLUSH_BEGIN(mm) - srmmu_flush_whole_tlb(); - module_stats.invrnge++; - FLUSH_END -} - -static void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - - FLUSH_BEGIN(mm) - __asm__ __volatile__(" - lda [%0] %3, %%g5 - sta %1, [%0] %3 - sta %%g0, [%2] %4 - sta %%g5, [%0] %3" - : /* no outputs */ - : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK), - "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) - : "g5"); - module_stats.invpg++; - FLUSH_END -} +/* tsunami.S */ +extern void tsunami_flush_cache_all(void); +extern void tsunami_flush_cache_mm(struct mm_struct *mm); +extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end); +extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page); +extern void tsunami_flush_page_to_ram(unsigned long page); +extern void tsunami_flush_page_for_dma(unsigned long page); +extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); +extern void tsunami_flush_chunk(unsigned long chunk); +extern void tsunami_flush_tlb_all(void); +extern void tsunami_flush_tlb_mm(struct mm_struct *mm); +extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); +extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); /* Swift flushes. It has the recommended SRMMU specification flushing * facilities, so we can do things in a more fine grained fashion than we @@ -1364,18 +1239,31 @@ extern void hypersparc_flush_tlb_all(void); extern void hypersparc_flush_tlb_mm(struct mm_struct *mm); extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void hypersparc_bzero_1page(void *); +extern void hypersparc_copy_1page(void *, const void *); + +static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) +{ + unsigned long page = ((unsigned long)ptep) & PAGE_MASK; + + srmmu_set_entry(ptep, pte_val(pteval)); + hypersparc_flush_page_to_ram(page); +} static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) { + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); hyper_flush_whole_icache(); - set_pte((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)))); } static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; - hypersparc_flush_page_to_ram(page); + if(pgdp != swapper_pg_dir) + hypersparc_flush_page_to_ram(page); + if(tsk->mm->context != NO_CONTEXT) { flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); @@ -1429,26 +1317,29 @@ static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) static void hypersparc_switch_to_context(struct task_struct *tsk) { - hyper_flush_whole_icache(); if(tsk->mm->context == NO_CONTEXT) { + ctxd_t *ctxp; + alloc_context(tsk->mm); - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); - flush_tlb_mm(tsk->mm); + ctxp = &srmmu_context_table[tsk->mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); } + hyper_flush_whole_icache(); srmmu_set_context(tsk->mm->context); } static void hypersparc_init_new_context(struct mm_struct *mm) { - hyper_flush_whole_icache(); + ctxd_t *ctxp; alloc_context(mm); - flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], mm->pgd); - flush_tlb_mm(mm); + ctxp = &srmmu_context_table[mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); + hyper_flush_whole_icache(); if(mm == current->mm) srmmu_set_context(mm->context); } @@ -2150,6 +2041,32 @@ check_and_return: MKTRACE(("success\n")); init_task.mm->mmap->vm_start = page_offset = low_base; stack_top = page_offset - PAGE_SIZE; +#if 1 + for(entry = 0; srmmu_map[entry].size; entry++) { + printk("[%d]: v[%08lx,%08lx](%lx) p[%08lx]\n", entry, + srmmu_map[entry].vbase, + srmmu_map[entry].vbase + srmmu_map[entry].size, + srmmu_map[entry].size, + srmmu_map[entry].pbase); + } +#endif + + /* Now setup the p2v/v2p hash tables. */ + for(entry = 0; entry < SRMMU_HASHSZ; entry++) + srmmu_v2p_hash[entry] = srmmu_p2v_hash[entry] = NULL; + for(entry = 0; srmmu_map[entry].size; entry++) { + unsigned long addr; + + for(addr = srmmu_map[entry].vbase; + addr < (srmmu_map[entry].vbase + srmmu_map[entry].size); + addr += (1 << 24)) + srmmu_v2p_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry]; + for(addr = srmmu_map[entry].pbase; + addr < (srmmu_map[entry].pbase + srmmu_map[entry].size); + addr += (1 << 24)) + srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry]; + } + return; /* SUCCESS! */ } @@ -2338,7 +2255,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, start += PAGE_SIZE; } } - } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap); + } while ((vmaring = vmaring->vm_next_share) != NULL); if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = srmmu_pgd_offset(vma->vm_mm, address); @@ -2355,13 +2272,19 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, static void hypersparc_destroy_context(struct mm_struct *mm) { if(mm->context != NO_CONTEXT && mm->count == 1) { + ctxd_t *ctxp; + /* HyperSparc is copy-back, any data for this * process in a modified cache line is stale * and must be written back to main memory now * else we eat shit later big time. */ flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + + ctxp = &srmmu_context_table[mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); + flush_tlb_mm(mm); free_context(mm->context); mm->context = NO_CONTEXT; @@ -2450,6 +2373,11 @@ static void poke_hypersparc(void) hyper_flush_whole_icache(); clear = srmmu_get_faddr(); clear = srmmu_get_fstatus(); + +#ifdef __SMP__ + /* Avoid unnecessary cross calls. */ + flush_page_for_dma = local_flush_page_for_dma; +#endif } __initfunc(static void init_hypersparc(void)) @@ -2482,6 +2410,14 @@ __initfunc(static void init_hypersparc(void)) update_mmu_cache = srmmu_vac_update_mmu_cache; sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir; poke_srmmu = poke_hypersparc; + + /* High performance page copy/clear. */ + { extern void (*__copy_1page)(void *, const void *); + extern void (*bzero_1page)(void *); + + __copy_1page = hypersparc_copy_1page; + bzero_1page = hypersparc_bzero_1page; + } } static void poke_cypress(void) @@ -3014,9 +2950,7 @@ __initfunc(void ld_mmu_srmmu(void)) mmu_p2v = srmmu_p2v; /* Task struct and kernel stack allocating/freeing. */ - alloc_kernel_stack = srmmu_alloc_kernel_stack; alloc_task_struct = srmmu_alloc_task_struct; - free_kernel_stack = srmmu_free_kernel_stack; free_task_struct = srmmu_free_task_struct; quick_kernel_fault = srmmu_quick_kernel_fault; diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index ebeada4c7..a0ffc10ed 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $ +/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -1093,8 +1093,7 @@ static void sun4c_quick_kernel_fault(unsigned long address) panic("sun4c kernel fault handler bolixed..."); } -/* - * 4 page buckets for task struct and kernel stack allocation. +/* 2 page buckets for task struct and kernel stack allocation. * * TASK_STACK_BEGIN * bucket[0] @@ -1105,24 +1104,17 @@ static void sun4c_quick_kernel_fault(unsigned long address) * * Each slot looks like: * - * page 1 -- task struct - * page 2 -- unmapped, for stack redzone (maybe use for pgd) - * page 3/4 -- kernel stack + * page 1 -- task struct + beginning of kernel stack + * page 2 -- rest of kernel stack */ -struct task_bucket { - struct task_struct task; - char _unused1[PAGE_SIZE - sizeof(struct task_struct)]; - char kstack[(PAGE_SIZE*3)]; -}; - -struct task_bucket *sun4c_bucket[NR_TASKS]; +union task_union *sun4c_bucket[NR_TASKS]; static int sun4c_lowbucket_avail; -#define BUCKET_EMPTY ((struct task_bucket *) 0) -#define BUCKET_SIZE (PAGE_SIZE << 2) -#define BUCKET_SHIFT 14 /* log2(sizeof(struct task_bucket)) */ +#define BUCKET_EMPTY ((union task_union *) 0) +#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */ +#define BUCKET_SIZE (1 << BUCKET_SHIFT) #define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT)) #define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR) #define BUCKET_PTE(page) \ @@ -1177,10 +1169,10 @@ static inline void garbage_collect(int entry) { int start, end; - /* 16 buckets per segment... */ - entry &= ~15; + /* 32 buckets per segment... */ + entry &= ~31; start = entry; - for(end = (start + 16); start < end; start++) + for(end = (start + 32); start < end; start++) if(sun4c_bucket[start] != BUCKET_EMPTY) return; @@ -1190,121 +1182,70 @@ static inline void garbage_collect(int entry) static struct task_struct *sun4c_alloc_task_struct(void) { - unsigned long addr, page; + unsigned long addr, pages; int entry; - page = get_free_page(GFP_KERNEL); - if(!page) + pages = __get_free_pages(GFP_KERNEL, 1, 0); + if(!pages) return (struct task_struct *) 0; for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++) if(sun4c_bucket[entry] == BUCKET_EMPTY) break; if(entry == NR_TASKS) { - free_page(page); + free_pages(pages, 1); return (struct task_struct *) 0; } if(entry >= sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry + 1; addr = BUCKET_ADDR(entry); - sun4c_bucket[entry] = (struct task_bucket *) addr; + sun4c_bucket[entry] = (union task_union *) addr; if(sun4c_get_segmap(addr) == invalid_segment) get_locked_segment(addr); - sun4c_put_pte(addr, BUCKET_PTE(page)); + sun4c_put_pte(addr, BUCKET_PTE(pages)); + sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); return (struct task_struct *) addr; } -static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk) -{ - unsigned long saddr = (unsigned long) tsk; - unsigned long page[2]; - - if(!saddr) - return 0; - page[0] = __get_free_page(GFP_KERNEL); - if(!page[0]) - return 0; - page[1] = __get_free_page(GFP_KERNEL); - if(!page[1]) { - free_page(page[0]); - return 0; - } - - saddr += PAGE_SIZE << 1; - sun4c_put_pte(saddr, BUCKET_PTE(page[0])); - sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1])); - return saddr; -} - -static void sun4c_free_kernel_stack_hw(unsigned long stack) -{ - unsigned long page[2]; - - page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); - page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); - - /* We are deleting a mapping, so the flushes here are mandatory. */ - sun4c_flush_page_hw(stack); - sun4c_flush_page_hw(stack + PAGE_SIZE); - - sun4c_put_pte(stack, 0); - sun4c_put_pte(stack + PAGE_SIZE, 0); - free_page(page[0]); - free_page(page[1]); -} - static void sun4c_free_task_struct_hw(struct task_struct *tsk) { unsigned long tsaddr = (unsigned long) tsk; - unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); + unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); /* We are deleting a mapping, so the flush here is mandatory. */ sun4c_flush_page_hw(tsaddr); + sun4c_flush_page_hw(tsaddr + PAGE_SIZE); sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); sun4c_bucket[entry] = BUCKET_EMPTY; if(entry < sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry; - free_page(page); + free_pages(pages, 1); garbage_collect(entry); } -static void sun4c_free_kernel_stack_sw(unsigned long stack) -{ - unsigned long page[2]; - - page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); - page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); - - /* We are deleting a mapping, so the flushes here are mandatory. */ - sun4c_flush_page_sw(stack); - sun4c_flush_page_sw(stack + PAGE_SIZE); - - sun4c_put_pte(stack, 0); - sun4c_put_pte(stack + PAGE_SIZE, 0); - free_page(page[0]); - free_page(page[1]); -} - static void sun4c_free_task_struct_sw(struct task_struct *tsk) { unsigned long tsaddr = (unsigned long) tsk; - unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); + unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); /* We are deleting a mapping, so the flush here is mandatory. */ sun4c_flush_page_sw(tsaddr); + sun4c_flush_page_sw(tsaddr + PAGE_SIZE); sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); sun4c_bucket[entry] = BUCKET_EMPTY; if(entry < sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry; - free_page(page); + free_pages(pages, 1); garbage_collect(entry); } @@ -1312,8 +1253,8 @@ __initfunc(static void sun4c_init_buckets(void)) { int entry; - if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) { - prom_printf("task bucket not 4 pages!\n"); + if(sizeof(union task_union) != (PAGE_SIZE << 1)) { + prom_printf("task union not 2 pages!\n"); prom_halt(); } for(entry = 0; entry < NR_TASKS; entry++) @@ -2526,7 +2467,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr start += PAGE_SIZE; } } - } while ((vmaring = vmaring->vm_next_share) != inode->i_mmap); + } while ((vmaring = vmaring->vm_next_share) != NULL); if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); @@ -2645,7 +2586,6 @@ __initfunc(void ld_mmu_sun4c(void)) flush_tlb_mm = sun4c_flush_tlb_mm_hw; flush_tlb_range = sun4c_flush_tlb_range_hw; flush_tlb_page = sun4c_flush_tlb_page_hw; - free_kernel_stack = sun4c_free_kernel_stack_hw; free_task_struct = sun4c_free_task_struct_hw; switch_to_context = sun4c_switch_to_context_hw; destroy_context = sun4c_destroy_context_hw; @@ -2658,7 +2598,6 @@ __initfunc(void ld_mmu_sun4c(void)) flush_tlb_mm = sun4c_flush_tlb_mm_sw; flush_tlb_range = sun4c_flush_tlb_range_sw; flush_tlb_page = sun4c_flush_tlb_page_sw; - free_kernel_stack = sun4c_free_kernel_stack_sw; free_task_struct = sun4c_free_task_struct_sw; switch_to_context = sun4c_switch_to_context_sw; destroy_context = sun4c_destroy_context_sw; @@ -2736,7 +2675,6 @@ __initfunc(void ld_mmu_sun4c(void)) mmu_p2v = sun4c_p2v; /* Task struct and kernel stack allocating/freeing. */ - alloc_kernel_stack = sun4c_alloc_kernel_stack; alloc_task_struct = sun4c_alloc_task_struct; quick_kernel_fault = sun4c_quick_kernel_fault; diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S new file mode 100644 index 000000000..2a598cd7b --- /dev/null +++ b/arch/sparc/mm/tsunami.S @@ -0,0 +1,90 @@ +/* $Id: tsunami.S,v 1.1 1997/05/03 05:09:09 davem Exp $ + * tsunami.S: High speed MicroSparc-I mmu/cache operations. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <asm/ptrace.h> +#include <asm/psr.h> +#include <asm/asi.h> +#include <asm/page.h> +#include <asm/pgtsrmmu.h> + +#define WINDOW_FLUSH(tmp1, tmp2) \ + mov 0, tmp1; \ +98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ + orcc %g0, tmp2, %g0; \ + add tmp1, 1, tmp1; \ + bne 98b; \ + save %sp, -64, %sp; \ +99: subcc tmp1, 1, tmp1; \ + bne 99b; \ + restore %g0, %g0, %g0; + + .text + .align 4 + + .globl tsunami_flush_cache_all, tsunami_flush_cache_mm + .globl tsunami_flush_cache_range, tsunami_flush_cache_page + .globl tsunami_flush_page_to_ram, tsunami_flush_page_for_dma + .globl tsunami_flush_sig_insns, tsunami_flush_chunk + .globl tsunami_flush_tlb_all, tsunami_flush_tlb_mm + .globl tsunami_flush_tlb_range, tsunami_flush_tlb_page + + /* Sliiick... */ +tsunami_flush_cache_page: + ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */ +tsunami_flush_cache_mm: +tsunami_flush_cache_range: + ld [%o0 + AOFF_mm_context], %g2 +#ifndef __SMP__ + cmp %g2, -1 + be tsunami_flush_cache_out +#endif +tsunami_flush_cache_all: + WINDOW_FLUSH(%g4, %g5) +tsunami_flush_page_for_dma: + sta %g0, [%g0] ASI_M_DC_FLCLEAR + sta %g0, [%g0] ASI_M_IC_FLCLEAR +tsunami_flush_cache_out: +tsunami_flush_page_to_ram: +tsunami_flush_chunk: + retl + nop + +tsunami_flush_sig_insns: + flush %o1 + retl + flush %o1 + 4 + + /* More slick stuff... */ +tsunami_flush_tlb_mm: +tsunami_flush_tlb_range: +#ifndef __SMP__ + ld [%o0 + AOFF_mm_context], %g2 + cmp %g2, -1 + be tsunami_flush_tlb_out +#endif +tsunami_flush_tlb_all: + mov 0x400, %o1 + sta %g0, [%o1] ASI_M_FLUSH_PROBE +tsunami_flush_tlb_out: + retl + nop + + /* This one can be done in a fine grained manner... */ +tsunami_flush_tlb_page: + ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ + mov SRMMU_CTX_REG, %g1 + ld [%o0 + AOFF_mm_context], %o3 + andn %o1, (PAGE_SIZE - 1), %o1 +#ifndef __SMP__ + cmp %o3, -1 + be tsunami_flush_tlb_page_out +#endif + lda [%g1] ASI_M_MMUREGS, %g5 + sta %o3, [%g1] ASI_M_MMUREGS + sta %g0, [%o1] ASI_M_FLUSH_PROBE +tsunami_flush_tlb_page_out: + retl + sta %g5, [%g1] ASI_M_MMUREGS diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S index f61aa4398..19d426ec7 100644 --- a/arch/sparc/mm/viking.S +++ b/arch/sparc/mm/viking.S @@ -1,4 +1,4 @@ -/* $Id: viking.S,v 1.2 1997/04/20 21:21:49 ecd Exp $ +/* $Id: viking.S,v 1.3 1997/05/04 10:02:14 ecd Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -38,40 +38,26 @@ viking_flush_page: viking_flush_chunk: - sethi %hi(C_LABEL(srmmu_map)), %g2 - or %g2, %lo(C_LABEL(srmmu_map)), %g3 - ld [%g3 + 8], %g2 - cmp %g2, 0 - be 3f + sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 + or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2 + srl %o0, 24, %o1 + sll %o1, 2, %o1 + + ld [%g2 + %o1], %g3 + cmp %g3, 0 + bne 1f and %o0, PAGE_MASK, %o0 - ld [%g3], %o1 -1: - cmp %o1, %o0 - bgu,a 2f - add %g3, 0xc, %g3 - - add %o1, %g2, %g2 - cmp %g2, %o0 - bleu,a 2f - add %g3, 0xc, %g3 + retl + nop +1: + ld [%g3], %o1 sub %o0, %o1, %g2 ld [%g3 + 4], %o0 add %g2, %o0, %g3 - b 4f - srl %g3, 12, %g1 ! ppage >> 12 - -2: - ld [%g3 + 8], %g2 - cmp %g2, 0 - bne,a 1b - ld [%g3], %o1 -3: - retl - nop + srl %g3, 12, %g1 ! ppage >> 12 -4: clr %o1 ! set counter, 0 - 127 sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3 sethi %hi(0x80000000), %o4 @@ -131,40 +117,27 @@ viking_flush_chunk: viking_mxcc_flush_page: - sethi %hi(C_LABEL(srmmu_map)), %g2 - or %g2, %lo(C_LABEL(srmmu_map)), %g3 - ld [%g3 + 8], %g2 - cmp %g2, 0 - be 3f + sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 + or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2 + srl %o0, 24, %o1 + sll %o1, 2, %o1 + + ld [%g2 + %o1], %g3 + cmp %g3, 0 + bne 1f and %o0, PAGE_MASK, %o0 - ld [%g3], %o1 -1: - cmp %o1, %o0 - bgu,a 2f - add %g3, 0xc, %g3 - - add %o1, %g2, %g2 - cmp %g2, %o0 - bleu,a 2f - add %g3, 0xc, %g3 + retl + nop +1: + ld [%g3], %o1 sub %o0, %o1, %g2 ld [%g3 + 4], %o0 + sethi %hi(PAGE_SIZE), %g4 add %g2, %o0, %g3 - sethi %hi(PAGE_SIZE), %g4 - b 4f - add %g3, %g4, %g3 ! ppage + PAGE_SIZE - -2: - ld [%g3 + 8], %g2 - cmp %g2, 0 - bne,a 1b - ld [%g3], %o1 -3: - retl - nop -4: + add %g3, %g4, %g3 ! ppage + PAGE_SIZE + mov 0x10, %g2 ! set cacheable bit sethi %hi(MXCC_SRCSTREAM), %o2 or %o2, %lo(MXCC_SRCSTREAM), %o2 diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c index 9551094d0..4c999477b 100644 --- a/arch/sparc/prom/console.c +++ b/arch/sparc/prom/console.c @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $ +/* $Id: console.c,v 1.14 1997/05/14 20:44:58 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -14,6 +14,9 @@ #include <asm/system.h> #include <linux/string.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Non blocking get character from console input device, returns -1 * if no input was taken. This can be used for polling. */ @@ -38,11 +41,12 @@ prom_nbgetchar(void) } break; case PROM_AP1000: + default: i = -1; break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ @@ -81,9 +85,12 @@ prom_nbputchar(char c) #endif break; + default: + i = -1; + break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ @@ -130,7 +137,7 @@ prom_query_input_device() save_flags(flags); cli(); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); if(prom_node_has_property(st_p, "keyboard")) @@ -177,7 +184,7 @@ prom_query_output_device() save_flags(flags); cli(); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); @@ -208,6 +215,7 @@ prom_query_output_device() } break; case PROM_AP1000: + default: return PROMDEV_I_UNK; }; return PROMDEV_O_UNK; diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c index 841d63a47..cd99ac3d6 100644 --- a/arch/sparc/prom/devmap.c +++ b/arch/sparc/prom/devmap.c @@ -1,4 +1,4 @@ -/* $Id: devmap.c,v 1.3 1996/09/19 20:27:19 davem Exp $ +/* $Id: devmap.c,v 1.5 1997/05/14 20:44:59 davem Exp $ * promdevmap.c: Map device/IO areas to virtual addresses. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,9 @@ #include <asm/openprom.h> #include <asm/oplib.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Just like the routines in palloc.c, these should not be used * by the kernel at all. Bootloader facility mainly. And again, * this is only available on V2 proms and above. @@ -33,7 +36,7 @@ prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes) ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr, num_bytes); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return ret; @@ -49,7 +52,7 @@ prom_unmapio(char *vaddr, unsigned int num_bytes) save_flags(flags); cli(); (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return; diff --git a/arch/sparc/prom/devops.c b/arch/sparc/prom/devops.c index 2b33dd2b7..f7feb0815 100644 --- a/arch/sparc/prom/devops.c +++ b/arch/sparc/prom/devops.c @@ -1,4 +1,4 @@ -/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $ +/* $Id: devops.c,v 1.10 1997/05/14 20:44:59 davem Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -10,6 +10,9 @@ #include <asm/openprom.h> #include <asm/oplib.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Open the device described by the string 'dstr'. Returns the handle * to that device used for subsequent operations on that device. * Returns -1 on failure. @@ -35,7 +38,7 @@ prom_devopen(char *dstr) break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -57,10 +60,11 @@ prom_devclose(int dhandle) (*(romvec->pv_v2devops.v2_dev_close))(dhandle); break; case PROM_AP1000: + default: break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return 0; @@ -83,10 +87,11 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo); break; case PROM_AP1000: + default: break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c index d23d93f61..fede033dd 100644 --- a/arch/sparc/prom/misc.c +++ b/arch/sparc/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $ +/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -13,6 +13,9 @@ #include <asm/oplib.h> #include <asm/auxio.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(char *bcommand) @@ -22,7 +25,7 @@ prom_reboot(char *bcommand) (*(romvec->pv_reboot))(bcommand); /* Never get here. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); } @@ -40,7 +43,7 @@ prom_feval(char *fstring) else (*(romvec->pv_fortheval.v2_eval))(fstring); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); } @@ -72,7 +75,7 @@ prom_cmdline(void) save_flags(flags); cli(); (*(romvec->pv_abort))(); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); install_linux_ticker(); @@ -97,7 +100,7 @@ again: (*(romvec->pv_halt))(); /* Never get here. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); goto again; /* PROM is out to get me -DaveM */ diff --git a/arch/sparc/prom/mp.c b/arch/sparc/prom/mp.c index cf71cca60..8f07f9d40 100644 --- a/arch/sparc/prom/mp.c +++ b/arch/sparc/prom/mp.c @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $ +/* $Id: mp.c,v 1.9 1997/05/14 20:45:01 davem Exp $ * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * @@ -12,6 +12,9 @@ #include <asm/openprom.h> #include <asm/oplib.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Start cpu with prom-tree node 'cpunode' using context described * by 'ctable_reg' in context 'ctx' at program counter 'pc'. * @@ -36,7 +39,7 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -65,7 +68,7 @@ prom_stopcpu(int cpunode) break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -94,7 +97,7 @@ prom_idlecpu(int cpunode) break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -123,7 +126,7 @@ prom_restartcpu(int cpunode) break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c index cb1def0e1..96b543727 100644 --- a/arch/sparc/prom/segment.c +++ b/arch/sparc/prom/segment.c @@ -1,4 +1,4 @@ -/* $Id: segment.c,v 1.3 1996/09/19 20:27:28 davem Exp $ +/* $Id: segment.c,v 1.5 1997/05/14 20:45:02 davem Exp $ * segment.c: Prom routine to map segments in other contexts before * a standalone is completely mapped. This is for sun4 and * sun4c architectures only. @@ -12,6 +12,9 @@ #include <asm/openprom.h> #include <asm/oplib.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; + /* Set physical segment 'segment' at virtual address 'vaddr' in * context 'ctx'. */ @@ -22,7 +25,7 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment) save_flags(flags); cli(); (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return; diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c index e5e2ceb3d..251b2ee6a 100644 --- a/arch/sparc/prom/tree.c +++ b/arch/sparc/prom/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $ +/* $Id: tree.c,v 1.18 1997/05/14 20:45:03 davem Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -15,10 +15,12 @@ #include <asm/openprom.h> #include <asm/oplib.h> +/* XXX Let's get rid of this thing if we can... */ +extern struct task_struct *current_set[NR_CPUS]; /* Macro to restore "current" to the g6 register. */ #define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \ - "r" (¤t_set[smp_processor_id()]) : \ + "r" (¤t_set[hard_smp_processor_id()]) : \ "memory") static char promlib_buf[128]; diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index bacf9b095..a70f9ebf8 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 1997/04/14 17:04:49 jj Exp $ +# $Id: Makefile,v 1.16 1997/05/04 07:21:08 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -29,7 +29,7 @@ CFLAGS := $(CFLAGS) -pipe \ LINKFLAGS = -T arch/sparc64/vmlinux.lds -HEAD := arch/sparc64/kernel/head.o +HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \ arch/sparc64/prom diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 9ecbf90b4..fbc4a5073 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -40,6 +40,7 @@ SUN_FB_CGFOURTEEN=y SUN_FB_BWTWO=y SUN_FB_LEO=y TADPOLE_FB_WEITEK=y +SUN_FB_CREATOR=y # # Misc Linux/SPARC drivers @@ -132,8 +133,8 @@ CONFIG_SUNLANCE=y # # Filesystems # -CONFIG_QUOTA=y -CONFIG_MINIX_FS=y +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set @@ -141,7 +142,9 @@ CONFIG_EXT2_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set +CONFIG_ROOT_NFS=y +CONFIG_RNFS_BOOTP=y +# CONFIG_RNFS_RARP is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index d66fa06e7..4a07295e1 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.16 1997/04/17 20:35:37 jj Exp $ +# $Id: Makefile,v 1.20 1997/05/18 08:42:11 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -13,12 +13,12 @@ .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o -all: kernel.o head.o +all: kernel.o head.o init_task.o O_TARGET := kernel.o O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \ systbls.o traps.o entry.o devices.o auxio.o ioport.o \ - irq.o time.o sys_sparc.o + irq.o time.o sys_sparc.o signal.o winfixup.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_SPARC32_COMPAT @@ -26,12 +26,17 @@ ifdef CONFIG_SPARC32_COMPAT endif ifdef CONFIG_BINFMT_ELF32 - O_OBJS += sparcelf32.o + O_OBJS += binfmt_elf32.o endif head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o +# +# This is just to get the dependencies... +# +binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c + check_asm: dummy @echo "#include <linux/sched.h>" > tmp.c $(CC) -E tmp.c -o tmp.i diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c new file mode 100644 index 000000000..05d50fe56 --- /dev/null +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -0,0 +1,34 @@ +/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. + * + */ + +#define ELF_ARCH EM_SPARC +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; + +#include <asm/processor.h> +#include <linux/module.h> +#include <linux/config.h> + +#define elf_addr_t u32 +#define elf_caddr_t u32 +#undef start_thread +#define start_thread start_thread32 +#define init_elf_binfmt init_elf32_binfmt +#undef CONFIG_BINFMT_ELF +#ifdef CONFIG_BINFMT_ELF32 +#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32 +#endif +#undef CONFIG_BINFMT_ELF_MODULE +#ifdef CONFIG_BINFMT_ELF32_MODULE +#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE +#endif +#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT + +MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra"); +MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); + +#undef MODULE_DESCRIPTION +#undef MODULE_AUTHOR + +#include "../../../fs/binfmt_elf.c" diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S index 8eec19260..2cf372ca9 100644 --- a/arch/sparc64/kernel/dtlb_prot.S +++ b/arch/sparc64/kernel/dtlb_prot.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $ +/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $ * dtlb_prot.S: Data TLB protection code, this is included directly * into the trap table. * @@ -18,30 +18,30 @@ /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset /*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset - /*0x10*/ and %g4, %g2, %g3 ! Mask PMD offset + /*0x10*/ and %g4, %g2, %g4 ! Mask PMD offset /*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD - /*0x18*/ ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 ! Load PMD + /*0x18*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset /* ICACHE line 2 */ /*0x20*/ srlx %g1, 1, %g1 ! PTE offset /*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE /*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable? - /*0x2c*/ be,pt %xcc, sparc64_dtlb_fault ! Nope... + /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! Nope... /*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is /*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page - /*0x38*/ ldxa [%g5] ASI_DMMU, %g1 ! From MMU - /*0x3c*/ add %g2, 7, %g5 ! Compute mask + /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg + /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU /* ICACHE line 3 */ - /*0x40*/ andn %g1, %g5, %g1 ! Mask page - /*0x44*/ or %g1, 0x10, %g1 ! 2ndary Context - /*0x48*/ stxa %g0, [%g1] ASI_DMMU_DEMAP ! TLB flush page - /*0x4c*/ membar #Sync ! Synchronize - /*0x50*/ stxa %g3, [%g4 + %g1] ASI_PHYS_USE_EC ! Update sw PTE - /*0x54*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x58*/ retry ! Trap return - /*0x5c*/ nop + /*0x40*/ add %g2, 7, %g5 ! Compute mask + /*0x44*/ andn %g4, %g5, %g4 ! Mask page + /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context + /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page + /*0x50*/ membar #Sync ! Synchronize + /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE + /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x5c*/ retry ! Trap return /* ICACHE line 4 */ /*0x60*/ nop diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 16fe5c8a0..589d1661a 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $ +/* $Id: entry.S,v 1.21 1997/05/18 10:04:44 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -24,31 +24,70 @@ .text .align 4 -/* FIXME: This is still debugging hack */ - .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch -sparc64_dtlb_fault: + .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch + .globl sparc64_itlb_refbit_catch + + /* Note, DMMU SFAR not updated for fast tlb data access miss + * traps, so we must use tag access to find the right page. + * However for DMMU fast protection traps it is updated so + * we use, but we must also clear it _before_ we enable interrupts + * and save state because there is a race where we can push a user + * window right now in etrap, a protection fault happens (for example + * to update the dirty bit) and since we left crap in the sfsr + * it will not get updated properly. + */ +sparc64_dtlb_prot_catch: + wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g2 + ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + ldxa [%g0 + TLB_SFSR] %asi, %g4 + cmp %g2, 1 + stxa %g0, [%g0 + TLB_SFSR] %asi + bgu,a %icc, winfix_trampoline + rdpr %tpc, %g5 ba,pt %xcc, etrap rd %pc, %g7 - call sparc64_dtlb_fault_handler - nop + b,a,pt %xcc, 1f sparc64_dtlb_refbit_catch: + wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g2 + ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + cmp %g2, 1 + clr %g4 ! sfsr not updated for tlb misses + bgu,a %icc, winfix_trampoline + rdpr %tpc, %g5 ba,pt %xcc, etrap rd %pc, %g7 - call sparc64_dtlb_refbit_handler - add %sp, STACK_BIAS + REGWIN_SZ, %o0 +1: + mov %l5, %o4 ! raw tag access + mov %l4, %o5 ! raw sfsr + srlx %l5, PAGE_SHIFT, %o3 + clr %o1 ! text_fault == 0 + sllx %o3, PAGE_SHIFT, %o3 ! address + and %l4, 0x4, %o2 ! write == sfsr.W + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr + ba,a,pt %xcc, rtrap sparc64_itlb_refbit_catch: rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate ba,pt %xcc, etrap rd %pc, %g7 - call sparc64_dtlb_refbit_handler - nop + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3 + mov 1, %o1 ! text_fault == 1 + clr %o2 ! write == 0 + clr %o4 ! tag access (N/A) + clr %o5 ! raw sfsr (N/A) + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr + ba,a,pt %xcc, rtrap /* Note check out head.h, this code isn't even used for UP, * for SMP things will be different. In particular the data @@ -121,6 +160,7 @@ breakpoint_trap: ba,a,pt %xcc, rtrap .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall + .globl sys_sigsuspend, sys_sigreturn sys_pipe: sethi %hi(sparc_pipe), %g1 @@ -147,12 +187,35 @@ sys_sigpause: ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + nop + call syscall_trace + nop + ba,a,pt %xcc, rtrap + +sys_sigsuspend: + call do_sigsuspend + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 be,pt %icc, ret_sys_call - clr %o0 + nop call syscall_trace nop - ba,pt %xcc, ret_sys_call - clr %o0 + ba,a,pt %xcc, rtrap + +sys_sigreturn: + call do_sigreturn + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, ret_sys_call + nop + call syscall_trace + nop + ba,a,pt %xcc, rtrap /* This is how fork() was meant to be done, 11 instruction entry. -DaveM */ .globl sys_fork, sys_vfork, sys_clone @@ -200,7 +263,7 @@ linux_syscall_trace: .globl ret_from_syscall ret_from_syscall: ba,pt %xcc, ret_sys_call - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 /* Linux native and SunOS system calls enter here... */ .align 4 @@ -232,13 +295,18 @@ syscall_is_too_hard: call %l7 mov %i5, %o5 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0] - + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] +#if 0 + /* Debugging... */ + call syscall_trace_exit + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 +#endif .globl ret_sys_call ret_sys_call: ldx [%curptr + AOFF_task_flags], %l6 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3 cmp %o0, -ENOIOCTLCMD sllx %g2, 32, %g2 bgeu,pn %xcc, 1f @@ -247,34 +315,34 @@ ret_sys_call: /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 clr %l6 - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */ + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */ add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC] + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC] + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] 1: /* System call failure, set Carry condition code. * Also, get abs(errno) to return to the process. */ sub %g0, %o0, %o0 or %g3, %g2, %g3 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0] + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] mov 1, %l6 - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */ + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */ add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC] + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC] + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] linux_syscall_trace2: call syscall_trace add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC] + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC] + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] /* End of entry.S */ diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 7d293a88b..f936b3071 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,34 +1,39 @@ -/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $ +/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <asm/asi.h> #include <asm/pstate.h> #include <asm/ptrace.h> +#include <asm/page.h> #include <asm/spitfire.h> #include <asm/head.h> -/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */ + /* We assume that pstate, when entering this, has AG and + * IE bits set, MG and IG clear. + * + * We also guarentee for caller that AG %g4 and %g5 will have + * their values preserved and left in %l4 and %l5 respectively + * for him (fault handling needs this). + */ .text .align 32 .globl etrap, etrap_irq etrap: - rdpr %pil, %g4 + rdpr %pil, %g2 etrap_irq: rdpr %tstate, %g1 - sllx %g4, 20, %g4 - rdpr %tpc, %g2 - or %g1, %g4, %g1 - rdpr %tnpc, %g3 + sllx %g2, 20, %g2 + or %g1, %g2, %g1 /* What happens more often? etrap when already in priv or from userland? */ andcc %g1, TSTATE_PRIV, %g0 bne,a,pn %xcc, 1f - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 /* Just when going from userland to privileged mode, * we have to change this stuff. @@ -38,41 +43,48 @@ etrap_irq: * trap level until PRIMARY_CONTEXT is set to zero, else * we fall out of NUCLEUS too soon and crash hard. */ - rdpr %wstate, %g5 - mov PRIMARY_CONTEXT, %g7 - ldxa [%g7] ASI_DMMU, %g4 - mov SECONDARY_CONTEXT, %g6 - stxa %g0, [%g7] ASI_DMMU - stxa %g4, [%g6] ASI_DMMU - wrpr %g0, 0x0, %tl + mov PRIMARY_CONTEXT, %g1 + ldxa [%g1] ASI_DMMU, %g2 + stxa %g0, [%g1] ASI_DMMU - sll %g5, 3, %g5 - sethi %uhi(KERNBASE), %g4 - or %g4, %ulo(KERNBASE), %g4 - sethi %hi(current_set), %g6 - or %g6, %lo(current_set), %g6 - sllx %g4, 32, %g4 - wrpr %g5, %wstate - rdpr %canrestore, %g5 - ldx [%g6 + %g4], %g6 -#ifdef __SMP__ -/* FIXME: Fix the above insn for SMP */ -#endif - wrpr %g0, 0, %canrestore - wrpr %g5, 0, %otherwin - ba,pt %xcc, 2f - ldx [%g6 + AOFF_task_saved_kernel_stack], %g5 + mov SECONDARY_CONTEXT, %g1 + stxa %g2, [%g1] ASI_DMMU + + rd %pic, %g1 + sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 + or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 + add %g1, %g2, %g2 + rdpr %tstate, %g1 1: + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] + rdpr %tpc, %g1 + rdpr %tnpc, %g3 + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC] + rd %y, %g1 + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC] + stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y] + wrpr %g0, 0x0, %tl -2: - rd %y, %g4 - stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE] - stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC] - stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC] - stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y] rdpr %pstate, %g1 - save %g5, -STACK_BIAS, %sp + save %g2, -STACK_BIAS, %sp + + /* Must guarentee that here andcc of TSTATE_PRIV at the top is + * still valid in %ccr register. Don't show this trick to your + * mom. -DaveM + */ + bne,pn %xcc, 1f + rdpr %canrestore, %g3 + wrpr %g0, 0, %canrestore + wrpr %g3, 0, %otherwin + + rdpr %wstate, %g6 + sll %g6, 3, %g6 + wrpr %g6, %wstate + +1: mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 mov %g7, %l2 wrpr %l1, PSTATE_AG, %pstate stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] @@ -91,24 +103,13 @@ etrap_irq: stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate - sethi %uhi(KERNBASE), %g4 - or %g4, %ulo(KERNBASE), %g4 - sethi %hi(current_set), %g6 - or %g6, %lo(current_set), %g6 - sllx %g4, 32, %g4 + srlx %sp, 43, %g4 + rd %pic, %g6 jmpl %l2 + 0x4, %g0 - ldx [%g6 + %g4], %g6 -#ifdef __SMP__ -/* FIXME: Fix the above insn for SMP */ -#endif + sllx %g4, 43, %g4 .globl etraptl1 etraptl1: - rdpr %tl, %g4 rdpr %tstate, %g1 - sub %g4, 1, %g4 - rdpr %tpc, %g2 - rdpr %tnpc, %g3 - wrpr %g4, 0x0, %tl ba,pt %xcc, 1b - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S index 0aca22a77..034bda2d0 100644 --- a/arch/sparc64/kernel/hack.S +++ b/arch/sparc64/kernel/hack.S @@ -4,8 +4,6 @@ to compile... */ .text .align 8 - .globl _sigpause_common -_sigpause_common: retl;nop .globl breakpoint breakpoint: retl;nop .globl do_cee @@ -36,8 +34,6 @@ do_fpother_tl1: retl;nop do_iae: retl;nop .globl do_iae_tl1 do_iae_tl1: retl;nop - .globl do_ill -do_ill: retl;nop .globl do_ill_tl1 do_ill_tl1: retl;nop .globl do_irq @@ -48,8 +44,6 @@ do_irq_tl1: retl;nop do_lddfmna: retl;nop .globl do_lddfmna_tl1 do_lddfmna_tl1: retl;nop - .globl do_mna -do_mna: retl;nop .globl do_mna_tl1 do_mna_tl1: retl;nop .globl do_paw @@ -60,8 +54,6 @@ do_paw_tl1: retl;nop do_privact: retl;nop .globl do_privop do_privop: retl;nop - .globl do_signal -do_signal: retl;nop .globl do_stdfmna do_stdfmna: retl;nop .globl do_stdfmna_tl1 @@ -200,15 +192,7 @@ sunos_write: retl;nop sunos_writev: retl;nop .globl sys_ptrace sys_ptrace: retl;nop - .globl sys_sigreturn -sys_sigreturn: retl;nop - .globl sys_sigstack -sys_sigstack: retl;nop - .globl sys_sigsuspend -sys_sigsuspend: retl;nop .globl syscall_trace syscall_trace: retl;nop .globl sys32_ptrace sys32_ptrace: retl;nop - .globl do_sigpause -do_sigpause: retl;nop diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index fdbe87aa3..4babe3eb4 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $ +/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -262,16 +262,22 @@ sun4u_init: stx %g6, [%g2 + %g4] stx %g5, [%g3 + %g4] - sethi %hi(init_task), %g6 - or %g6, %lo(init_task), %g6 + sethi %hi(init_task_union), %g6 + or %g6, %lo(init_task_union), %g6 add %g6, %g4, %g6 ! g6 usage is fixed as well mov %sp, %l6 mov %o4, %l7 - sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 - or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 - add %g5, %g4, %sp + /* Setup "Linux Current Register", thanks Sun 8-) */ + wr %g0, 0x1, %pcr + wr %g6, 0x0, %pic + + mov 1, %g5 + sllx %g5, (PAGE_SHIFT + 1), %g5 + sub %g5, (REGWIN_SZ + STACK_BIAS), %g5 + add %g6, %g5, %sp mov 0, %fp + wrpr %g0, 0, %wstate wrpr %g0, 0x0, %tl @@ -287,14 +293,20 @@ sun4u_init: add %l2, 1, %l2 add %l0, %g4, %o0 1: - call bzero_1page + clr %o1 + sethi %hi(PAGE_SIZE), %o2 + or %o2, %lo(PAGE_SIZE), %o2 + call __memset add %l0, %l2, %l0 cmp %l0, %l1 blu,pt %xcc, 1b add %l0, %g4, %o0 /* Now clear empty_zero_page */ - call bzero_1page + clr %o1 + sethi %hi(PAGE_SIZE), %o2 + or %o2, %lo(PAGE_SIZE), %o2 + call __memset mov %g4, %o0 mov %l6, %o1 ! OpenPROM stack @@ -361,6 +373,9 @@ bootup_kernel_stack: #include "ttable.S" + /* This is just anal retentiveness on my part... */ + .align 16384 + .data .align 8 .globl nwindows, nwindowsm1 diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c new file mode 100644 index 000000000..d0fc09346 --- /dev/null +++ b/arch/sparc64/kernel/init_task.c @@ -0,0 +1,18 @@ +#include <linux/mm.h> +#include <linux/sched.h> + +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* .text section in head.S is aligned at 2 page boundry and this gets linked + * right after that so that the init_task_union is aligned properly as well. + * We really don't need this special alignment like the Intel does, but + * I do it anyways for completeness. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 5ec62a6b6..4e2bbe016 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $ +/* $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -346,7 +346,14 @@ void flush_thread(void) } /* Now, this task is no longer a kernel thread. */ - current->tss.flags &= ~SPARC_FLAG_KTHREAD; + if(current->tss.flags & SPARC_FLAG_KTHREAD) { + current->tss.flags &= ~SPARC_FLAG_KTHREAD; + + /* exec_mmap() set context to NO_CONTEXT, here is + * where we grab a new one. + */ + get_mmu_context(current); + } current->tss.current_ds = USER_DS; } @@ -416,6 +423,64 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) return sp; } +/* Standard stuff. */ +static inline void shift_window_buffer(int first_win, int last_win, + struct thread_struct *tp) +{ + int i; + + for(i = first_win; i < last_win; i++) { + tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1]; + memcpy(&tp->reg_window[i], &tp->reg_window[i+1], + sizeof(struct reg_window)); + } +} + +void synchronize_user_stack(void) +{ + struct thread_struct *tp = ¤t->tss; + unsigned long window = tp->w_saved; + + flush_user_windows(); + if(window) { + int winsize = REGWIN_SZ; + + if(tp->flags & SPARC_FLAG_32BIT) + winsize = REGWIN32_SZ; + + window -= 1; + do { + unsigned long sp = tp->rwbuf_stkptrs[window]; + struct reg_window *rwin = &tp->reg_window[window]; + + if(!copy_to_user((char *)sp, rwin, winsize)) { + shift_window_buffer(window, tp->w_saved - 1, tp); + tp->w_saved--; + } + } while(window--); + } +} + +void fault_in_user_windows(struct pt_regs *regs) +{ + struct thread_struct *tp = ¤t->tss; + unsigned long window = tp->w_saved; + int winsize = REGWIN_SZ; + + if(tp->flags & SPARC_FLAG_32BIT) + winsize = REGWIN32_SZ; + if(window) { + window -= 1; + do { + unsigned long sp = tp->rwbuf_stkptrs[window]; + struct reg_window *rwin = &tp->reg_window[window]; + + if(copy_to_user((char *)sp, rwin, winsize)) + do_exit(SIGILL); + } while(window--); + } + current->tss.w_saved = 0; +} /* Copy a Sparc thread. The fork() return value conventions * under SunOS are nothing short of bletcherous: @@ -453,19 +518,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, #endif /* Calculate offset to stack_frame & pt_regs */ - stack_offset = (PAGE_SIZE - TRACEREG_SZ); + stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); if(regs->tstate & TSTATE_PRIV) stack_offset -= REGWIN_SZ; - childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); + childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset)); *childregs = *regs; new_stack = (((struct reg_window *) childregs) - 1); old_stack = (((struct reg_window *) regs) - 1); *new_stack = *old_stack; - p->saved_kernel_stack = ((unsigned long) new_stack); - p->tss.ksp = p->saved_kernel_stack - STACK_BIAS; + p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS; p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; p->tss.kregs = childregs; @@ -485,7 +549,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.current_ds = USER_DS; #if 0 - if (sp != current->tss.kregs->u_regs[UREG_FP]) { + if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf *childstack; struct sparc_stackf *parentstack; @@ -494,8 +558,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, * Set some valid stack frames to give to the child. */ childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *) - current->tss.kregs->u_regs[UREG_FP]; + parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP]; #if 0 printk("clone: parent stack:\n"); diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index dfebd7ad8..1c4c4df04 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $ +/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -71,12 +71,11 @@ rtrap: /* We came here from to_user, ie. we have now AG. * Also have to push user context back into primary. */ - restore - mov SECONDARY_CONTEXT, %g6 mov PRIMARY_CONTEXT, %g7 ldxa [%g6] ASI_DMMU, %g4 stxa %g4, [%g7] ASI_DMMU + membar #Sync /* XXX flushi would be better -DaveM */ rdpr %wstate, %g1 rdpr %otherwin, %g2 @@ -84,7 +83,6 @@ rtrap: wrpr %g2, %g0, %canrestore wrpr %g1, %g0, %wstate wrpr %g0, %g0, %otherwin - retry 1: restore retry @@ -101,9 +99,14 @@ to_user: ldx [%g6 + AOFF_task_blocked], %o0 or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate andncc %l0, %o0, %g0 - be,pt %xcc, 3b + be,pt %xcc, check_user_wins mov %l5, %o2 mov %l6, %o3 - add %sp, STACK_BIAS + REGWIN_SZ, %o1 call do_signal + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +check_user_wins: + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 3b + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call fault_in_user_windows add %o7, 3b-.-4, %o7 diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 170e5563e..47d900977 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $ +/* $Id: setup.c,v 1.6 1997/05/04 07:21:04 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -261,6 +261,8 @@ __initfunc(void setup_arch(char **cmdline_p, *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); + prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line); + printk("ARCH: SUN4U\n"); boot_flags_init(*cmdline_p); diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c new file mode 100644 index 000000000..1a595491a --- /dev/null +++ b/arch/sparc64/kernel/signal.c @@ -0,0 +1,438 @@ +/* $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $ + * arch/sparc64/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/ptrace.h> +#include <linux/unistd.h> +#include <linux/mm.h> + +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <asm/ptrace.h> +#include <asm/svr4.h> +#include <asm/pgtable.h> +#include <asm/fpumacro.h> +#include <asm/smp_lock.h> + +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); + +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, + unsigned long orig_o0, int ret_from_syscall); + +/* This turned off for production... */ +/* #define DEBUG_SIGNALS 1 */ + +/* + * The new signal frame, intended to be used for Linux applications only + * (we have enough in there to work with clone). + * All the interesting bits are in the info field. + */ + +struct new_signal_frame { + struct sparc_stackf ss; + __siginfo_t info; + __siginfo_fpu_t * fpu_save; + unsigned int insns [2]; + __siginfo_fpu_t fpu_state; +}; + +/* Align macros */ +#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) + +/* + * atomically swap in the new signal mask, and wait for a signal. + * This is really tricky on the Sparc, watch out... + */ +asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) +{ + unsigned int mask; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *); + _sigpause32_common(set, regs); + return; + } +#endif + spin_lock_irq(¤t->sigmask_lock); + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + + regs->tpc = regs->tnpc; + regs->tnpc += 4; + + /* Condition codes and return value where set here for sigpause, + * and so got used by setup_frame, which again causes sigreturn() + * to return -EINTR. + */ + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + /* + * Return -EINTR and set condition code here, + * so the interrupted system call actually returns + * these. + */ + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EINTR; + if (do_signal(mask, regs, 0, 0)) + return; + } +} + +asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs) +{ + _sigpause_common(set, regs); +} + +asmlinkage void do_sigsuspend(struct pt_regs *regs) +{ + _sigpause_common(regs->u_regs[UREG_I0], regs); +} + + +static inline void +restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) + regs->tstate &= ~(TSTATE_PEF); +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->tstate &= ~(TSTATE_PEF); + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; + + copy_from_user(¤t->tss.float_regs[0], + &fpu->si_float_regs[0], + (sizeof(unsigned int) * 64)); + __get_user(current->tss.fsr, &fpu->si_fsr); +} + +void do_sigreturn(struct pt_regs *regs) +{ + struct new_signal_frame *sf; + unsigned long tpc, tnpc, tstate; + __siginfo_fpu_t *fpu_save; + int mask; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + extern asmlinkage void do_sigreturn32(struct pt_regs *); + do_sigreturn32(regs); + return; + } +#endif + synchronize_user_stack (); + sf = (struct new_signal_frame *) regs->u_regs [UREG_FP]; + /* 1. Make sure we are not getting garbage from the user */ + if (verify_area (VERIFY_READ, sf, sizeof (*sf))){ + goto segv; + } + if (((unsigned long) sf) & 3){ + goto segv; + } + get_user(tpc, &sf->info.si_regs.tpc); + __get_user(tnpc, &sf->info.si_regs.tnpc); + if ((tpc | tnpc) & 3){ + goto segv; + } + regs->tpc = tpc; + regs->tnpc = tnpc; + + /* 2. Restore the state */ + __get_user(regs->y, &sf->info.si_regs.y); + __get_user(tstate, &sf->info.si_regs.tstate); + copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)); + + /* User can only change condition codes and FPU enabling in %tstate. */ + regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); + regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF)); + + __get_user(fpu_save, &sf->fpu_save); + if (fpu_save) + restore_fpu_state(regs, &sf->fpu_state); + __get_user(mask, &sf->info.si_mask); + current->blocked = mask & _BLOCKABLE; + return; +segv: + lock_kernel(); + do_exit(SIGSEGV); +} + +/* Checks if the fp is valid */ +static int invalid_frame_pointer(void *fp, int fplen) +{ + if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x80000000000ULL - fplen) + return 1; + return 0; +} + +static inline void +save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) { + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr); + regs->tstate &= ~(TSTATE_PEF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + fpsave((unsigned long *)¤t->tss.float_regs[0], ¤t->tss.fsr); + last_task_used_math = 0; + regs->tstate &= ~(TSTATE_PEF); + } +#endif + copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + (sizeof(unsigned int) * 64)); + __put_user(current->tss.fsr, &fpu->si_fsr); + current->used_math = 0; +} + +static inline void +new_setup_frame(struct sigaction *sa, struct pt_regs *regs, + int signo, unsigned long oldmask) +{ + struct new_signal_frame *sf; + int sigframe_size; + unsigned long tmp; + int i; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + sigframe_size = NF_ALIGNEDSZ; + if (!current->used_math) + sigframe_size -= sizeof(__siginfo_fpu_t); + + sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)){ + lock_kernel (); + do_exit(SIGILL); + } + + if (current->tss.w_saved != 0){ + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); + lock_kernel (); + do_exit (SIGILL); + } + + /* 2. Save the current process state */ + copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); + + if (current->used_math) { + save_fpu_state(regs, &sf->fpu_state); + __put_user((u64)&sf->fpu_state, &sf->fpu_save); + } else { + __put_user(0, &sf->fpu_save); + } + + __put_user(oldmask, &sf->info.si_mask); + for (i = 0; i < sizeof(struct reg_window)/8; i++) { + __get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i)); + __put_user(tmp, (((u64 *)sf)+i)); + } + + /* 3. return to kernel instructions */ + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */ + + /* 4. signal handler back-trampoline and parameters */ + regs->u_regs[UREG_FP] = (unsigned long) sf; + regs->u_regs[UREG_I0] = signo; + regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + /* 5. signal handler */ + regs->tpc = (unsigned long) sa->sa_handler; + regs->tnpc = (regs->tpc + 4); + + /* Flush instruction space. */ + __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0]))); + +} + +static inline void handle_signal(unsigned long signr, struct sigaction *sa, + unsigned long oldmask, struct pt_regs *regs) +{ + new_setup_frame(sa, regs, signr, oldmask); + if(sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + if(!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; +} + +static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, + struct sigaction *sa) +{ + switch(regs->u_regs[UREG_I0]) { + case ERESTARTNOHAND: + no_system_call_restart: + regs->u_regs[UREG_I0] = EINTR; + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + break; + case ERESTARTSYS: + if(!(sa->sa_flags & SA_RESTART)) + goto no_system_call_restart; + /* fallthrough */ + case ERESTARTNOINTR: + regs->u_regs[UREG_I0] = orig_i0; + regs->tpc -= 4; + regs->tnpc -= 4; + } +} + +/* Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, + unsigned long orig_i0, int restart_syscall) +{ + unsigned long signr, mask = ~current->blocked; + struct sigaction *sa; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + extern asmlinkage int do_signal32(unsigned long, struct pt_regs *, + unsigned long, int); + return do_signal32(oldmask, regs, orig_i0, restart_syscall); + } +#endif + while ((signr = current->signal & mask) != 0) { + signr = ffz(~signr); + clear_bit(signr, ¤t->signal); + sa = current->sig->action + signr; + signr++; + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + if (signr == SIGSTOP) + continue; + if (_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sig->action + signr - 1; + } + if(sa->sa_handler == SIG_IGN) { + if(signr != SIGCHLD) + continue; + + /* sys_wait4() grabs the master kernel lock, so + * we need not do so, that sucker should be + * threaded and would not be that difficult to + * do anyways. + */ + while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + ; + continue; + } + if(sa->sa_handler == SIG_DFL) { + if(current->pid == 1) + continue; + switch(signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + + case SIGSTOP: + if (current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: + if(current->binfmt && current->binfmt->core_dump) { + if(current->binfmt->core_dump(signr, regs)) + signr |= 0x80; + } +#ifdef DEBUG_SIGNALS + /* Very useful to debug dynamic linker problems */ + printk ("Sig ILL going...\n"); + show_regs (regs); +#endif + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + current->flags |= PF_SIGNALED; + do_exit(signr); + } + } + if(restart_syscall) + syscall_restart(orig_i0, regs, sa); + handle_signal(signr, sa, oldmask, regs); + return 1; + } + if(restart_syscall && + (regs->u_regs[UREG_I0] == ERESTARTNOHAND || + regs->u_regs[UREG_I0] == ERESTARTSYS || + regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { + /* replay the system call when we are done */ + regs->u_regs[UREG_I0] = orig_i0; + regs->tpc -= 4; + regs->tnpc -= 4; + } + return 0; +} + +asmlinkage int +sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr) +{ + int ret = -EFAULT; + + lock_kernel(); + /* First see if old state is wanted. */ + if(ossptr) { + if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) || + __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status)) + goto out; + } + + /* Now see if we want to update the new state. */ + if(ssptr) { + if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) || + __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status)) + goto out; + } + ret = 0; +out: + unlock_kernel(); + return ret; +} diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index e1129dfd6..d8e61511d 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $ +/* $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -30,8 +30,6 @@ #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -#define synchronize_user_stack() do { } while (0) - asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); @@ -117,17 +115,6 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) } } -asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs) -{ - _sigpause32_common(set, regs); -} - -asmlinkage void do_sigsuspend32(struct pt_regs *regs) -{ - _sigpause32_common(regs->u_regs[UREG_I0], regs); -} - - static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) { @@ -248,7 +235,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, { struct signal_sframe32 *sframep; struct sigcontext32 *sc; +#if 0 int window = 0; +#endif int old_status = current->tss.sstk_info.cur_status; unsigned psr; int i; @@ -424,7 +413,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, svr4_mcontext_t *mc; svr4_gwindows_t *gw; svr4_ucontext_t *uc; +#if 0 int window = 0; +#endif unsigned psr; int i; diff --git a/arch/sparc64/kernel/sparcelf32.c b/arch/sparc64/kernel/sparcelf32.c deleted file mode 100644 index 855c636e4..000000000 --- a/arch/sparc64/kernel/sparcelf32.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra. - * - * This is just binfmt_elf.c with hooks so that the types are those - * for a 32-bit ELF binaries. - */ - -/* This makes it work. */ -#define ELF_ARCH EM_SPARC -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB; - -/* - * linux/fs/binfmt_elf.c - * - * These are the functions used to load ELF format executables as used - * on SVr4 machines. Information on the format may be found in the book - * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support - * Tools". - * - * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). - */ - -#include <linux/module.h> - -#include <linux/fs.h> -#include <linux/stat.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/a.out.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/binfmts.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/malloc.h> -#include <linux/shm.h> -#include <linux/personality.h> -#include <linux/elfcore.h> -#include <linux/init.h> - -#include <asm/uaccess.h> -#include <asm/pgtable.h> - -#include <linux/config.h> - -#define DLINFO_ITEMS 12 - -#include <linux/elf.h> - -static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs); -static int load_elf32_library(int fd); -extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); -extern void dump_thread(struct pt_regs *, struct user *); - -extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); - -/* - * If we don't support core dumping, then supply a NULL so we - * don't even try. - */ -#ifdef USE_ELF_CORE_DUMP -static int elf32_core_dump(long signr, struct pt_regs * regs); -#else -#define elf32_core_dump NULL -#endif - -#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) -#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) - -static struct linux_binfmt elf32_format = { -#ifndef MODULE - NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump -#else - NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump -#endif -}; - -static void set_brk(unsigned long start, unsigned long end) -{ - start = PAGE_ALIGN(start); - end = PAGE_ALIGN(end); - if (end <= start) - return; - do_mmap(NULL, start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, 0); -} - - -/* We need to explicitly zero any fractional pages - after the data section (i.e. bss). This would - contain the junk from the file that should not - be in memory */ - - -static void padzero(unsigned long elf_bss) -{ - unsigned long nbyte; - - nbyte = elf_bss & (PAGE_SIZE-1); - if (nbyte) { - nbyte = PAGE_SIZE - nbyte; - clear_user((void *) elf_bss, nbyte); - } -} - -__u32 *create_elf32_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long interp_load_addr, int ibcs) -{ - __u32 *argv, *envp; - __u32 *sp, *csp; - - /* - * Force 16 byte alignment here for generality. - */ - sp = (__u32 *) (~15UL & (unsigned long) p); - csp = sp; - csp -= exec ? DLINFO_ITEMS*2 : 2; - csp -= envc+1; - csp -= argc+1; - if (!(((unsigned long) csp) & 4)) - sp--; - - /* - * Put the ELF interpreter info on the stack - */ -#define NEW_AUX_ENT(nr, id, val) \ - __put_user ((id), sp+(nr*2)); \ - __put_user ((val), sp+(nr*2+1)); \ - - sp -= 2; - NEW_AUX_ENT(0, AT_NULL, 0); - - if (exec) { - sp -= 11*2; - - NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE); - NEW_AUX_ENT (4, AT_BASE, interp_load_addr); - NEW_AUX_ENT (5, AT_FLAGS, 0); - NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry); - NEW_AUX_ENT (7, AT_UID, (__u32) current->uid); - NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid); - NEW_AUX_ENT (9, AT_GID, (__u32) current->gid); - NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid); - } -#undef NEW_AUX_ENT - - sp -= envc+1; - envp = (__u32 *) sp; - sp -= argc+1; - argv = (__u32 *) sp; - if (!ibcs) { - __put_user(((__u32)(long) envp),--sp); - __put_user(((__u32)(long) argv),--sp); - } - - __put_user((__u32)argc,--sp); - current->mm->arg_start = (unsigned long) p; - while (argc-->0) { - __put_user(((__u32)(long)p),argv++); - p += strlen_user(p); - } - __put_user(NULL, argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; - while (envc-->0) { - __put_user(((__u32)(long)p),envp++); - p += strlen_user(p); - } - __put_user(NULL, envp); - current->mm->env_end = (unsigned long) p; - return sp; -} - - -/* This is much more generalized than the library routine read function, - so we keep this separate. Technically the library read function - is only provided so that we can read a.out libraries that have - an ELF header */ - -static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex, - struct inode * interpreter_inode, - unsigned long *interp_load_addr) -{ - struct file * file; - struct elf_phdr *elf_phdata = NULL; - struct elf_phdr *eppnt; - unsigned long load_addr; - int load_addr_set = 0; - int elf_exec_fileno; - int retval; - unsigned long last_bss, elf_bss; - unsigned long error; - int i; - - elf_bss = 0; - last_bss = 0; - error = load_addr = 0; - - /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - !elf_check_arch(interp_elf_ex->e_machine) || - (!interpreter_inode->i_op || - !interpreter_inode->i_op->default_file_ops->mmap)){ - return ~0UL; - } - - /* Now read in all of the header information */ - - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) - return ~0UL; - - elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, - GFP_KERNEL); - if (!elf_phdata) - return ~0UL; - - /* - * If the size of this structure has changed, then punt, since - * we will be doing the wrong thing. - */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) - { - kfree(elf_phdata); - return ~0UL; - } - - retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, - (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); - - if (retval < 0) { - kfree (elf_phdata); - return retval; - } - - elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); - if (elf_exec_fileno < 0) { - kfree(elf_phdata); - return ~0UL; - } - - file = current->files->fd[elf_exec_fileno]; - - eppnt = elf_phdata; - for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; - - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; - } else { - load_addr = get_unmapped_area(0, eppnt->p_filesz + - ELF_PAGEOFFSET(eppnt->p_vaddr)); - } - - error = do_mmap(file, - load_addr + ELF_PAGESTART(vaddr), - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - - if (error > -1024UL) { - /* Real error */ - sys_close(elf_exec_fileno); - kfree(elf_phdata); - return ~0UL; - } - - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; - } - - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) elf_bss = k; - - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) last_bss = k; - } - - /* Now use mmap to map the library into memory. */ - - sys_close(elf_exec_fileno); - - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - padzero(elf_bss); - elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ - - /* Map the last of the bss segment */ - if (last_bss > elf_bss) - do_mmap(NULL, elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - kfree(elf_phdata); - - *interp_load_addr = load_addr; - return ((unsigned long) interp_elf_ex->e_entry) + load_addr; -} - -static unsigned long load_aout32_interp(struct exec * interp_ex, - struct inode * interpreter_inode) -{ - int retval; - unsigned long elf_entry; - - current->mm->brk = interp_ex->a_bss + - (current->mm->end_data = interp_ex->a_data + - (current->mm->end_code = interp_ex->a_text)); - elf_entry = interp_ex->a_entry; - - - if (N_MAGIC(*interp_ex) == OMAGIC) { - do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, - interp_ex->a_text+interp_ex->a_data, 0); - } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { - do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, - N_TXTOFF(*interp_ex) , - (char *) N_TXTADDR(*interp_ex), - interp_ex->a_text+interp_ex->a_data, 0); - } else - retval = -1; - - if (retval >= 0) - do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), - interp_ex->a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - if (retval < 0) return ~0UL; - return elf_entry; -} - -/* - * These are the functions used to load ELF style executables and shared - * libraries. There is no binary dependent code anywhere else. - */ - -#define INTERPRETER_NONE 0 -#define INTERPRETER_AOUT 1 -#define INTERPRETER_ELF 2 - - -static inline int -do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs) -{ - struct elfhdr elf_ex; - struct elfhdr interp_elf_ex; - struct file * file; - struct exec interp_ex; - struct inode *interpreter_inode; - unsigned long load_addr; - int load_addr_set = 0; - unsigned int interpreter_type = INTERPRETER_NONE; - unsigned char ibcs2_interpreter; - int i; - int old_fs; - int error; - struct elf_phdr * elf_ppnt, *elf_phdata; - int elf_exec_fileno; - unsigned long elf_bss, k, elf_brk; - int retval; - char * elf_interpreter; - unsigned long elf_entry, interp_load_addr = 0; - int status; - unsigned long start_code, end_code, end_data; - unsigned long elf_stack; - char passed_fileno[6]; - - ibcs2_interpreter = 0; - status = 0; - load_addr = 0; - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { - return -ENOEXEC; - } - - - /* First of all, some simple consistency checks */ - if ((elf_ex.e_type != ET_EXEC && - elf_ex.e_type != ET_DYN) || - (! elf_check_arch(elf_ex.e_machine)) || - (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || - !bprm->inode->i_op->default_file_ops->mmap)){ - return -ENOEXEC; - } - - /* Now read in all of the header information */ - - elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * - elf_ex.e_phnum, GFP_KERNEL); - if (elf_phdata == NULL) { - return -ENOMEM; - } - - retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, - elf_ex.e_phentsize * elf_ex.e_phnum, 1); - if (retval < 0) { - kfree (elf_phdata); - return retval; - } - - elf_ppnt = elf_phdata; - - elf_bss = 0; - elf_brk = 0; - - elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); - - if (elf_exec_fileno < 0) { - kfree (elf_phdata); - return elf_exec_fileno; - } - - file = current->files->fd[elf_exec_fileno]; - - elf_stack = ~0UL; - elf_interpreter = NULL; - start_code = ~0UL; - end_code = 0; - end_data = 0; - - for(i=0;i < elf_ex.e_phnum; i++){ - if (elf_ppnt->p_type == PT_INTERP) { - if ( elf_interpreter != NULL ) - { - kfree (elf_phdata); - kfree(elf_interpreter); - sys_close(elf_exec_fileno); - return -EINVAL; - } - - /* This is the program interpreter used for - * shared libraries - for now assume that this - * is an a.out format binary - */ - - elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, - GFP_KERNEL); - if (elf_interpreter == NULL) { - kfree (elf_phdata); - sys_close(elf_exec_fileno); - return -ENOMEM; - } - - retval = read_exec(bprm->inode,elf_ppnt->p_offset, - elf_interpreter, - elf_ppnt->p_filesz, 1); - /* If the program interpreter is one of these two, - then assume an iBCS2 image. Otherwise assume - a native linux image. */ - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) - ibcs2_interpreter = 1; -#if 0 - printk("Using ELF interpreter %s\n", elf_interpreter); -#endif - if (retval >= 0) { - old_fs = get_fs(); /* This could probably be optimized */ - set_fs(get_ds()); - retval = open_namei(elf_interpreter, 0, 0, - &interpreter_inode, NULL); - set_fs(old_fs); - } - - if (retval >= 0) - retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); - - if (retval >= 0) { - interp_ex = *((struct exec *) bprm->buf); /* exec-header */ - interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - - } - if (retval < 0) { - kfree (elf_phdata); - kfree(elf_interpreter); - sys_close(elf_exec_fileno); - return retval; - } - } - elf_ppnt++; - } - - /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ - interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; - - /* Now figure out which format our binary is */ - if ((N_MAGIC(interp_ex) != OMAGIC) && - (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) - interpreter_type = INTERPRETER_ELF; - - if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) - interpreter_type &= ~INTERPRETER_ELF; - - if (!interpreter_type) - { - kfree(elf_interpreter); - kfree(elf_phdata); - sys_close(elf_exec_fileno); - return -ELIBBAD; - } - } - - /* OK, we are done with that, now set up the arg stuff, - and then start this sucker up */ - - if (!bprm->sh_bang) { - char * passed_p; - - if (interpreter_type == INTERPRETER_AOUT) { - sprintf(passed_fileno, "%d", elf_exec_fileno); - passed_p = passed_fileno; - - if (elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); - bprm->argc++; - } - } - if (!bprm->p) { - if (elf_interpreter) { - kfree(elf_interpreter); - } - kfree (elf_phdata); - sys_close(elf_exec_fileno); - return -E2BIG; - } - } - - /* OK, This is the point of no return */ - flush_old_exec(bprm); - - current->mm->end_data = 0; - current->mm->end_code = 0; - current->mm->start_mmap = ELF_START_MMAP; - current->mm->mmap = NULL; - elf_entry = (unsigned long) elf_ex.e_entry; - - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ - current->mm->rss = 0; - bprm->p = setup_arg_pages(bprm->p, bprm); - current->mm->start_stack = bprm->p; - - /* Now we do a little grungy work by mmaping the ELF image into - the correct location in memory. At this point, we assume that - the image should be loaded at fixed address, not at a variable - address. */ - - old_fs = get_fs(); - set_fs(get_ds()); - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - if (elf_ppnt->p_type == PT_LOAD) { - int elf_prot = 0; - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - - error = do_mmap(file, - ELF_PAGESTART(elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | - MAP_DENYWRITE | MAP_EXECUTABLE), - (elf_ppnt->p_offset - - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - -#ifdef LOW_ELF_STACK - if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr); -#endif - - if (!load_addr_set) { - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - load_addr_set = 1; - } - k = elf_ppnt->p_vaddr; - if (k < start_code) start_code = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) elf_bss = k; -#if 1 - if ((elf_ppnt->p_flags & PF_X) && end_code < k) -#else - if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) -#endif - end_code = k; - if (end_data < k) end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; - } - } - set_fs(old_fs); - - if (elf_interpreter) { - if (interpreter_type & 1) - elf_entry = load_aout32_interp(&interp_ex, - interpreter_inode); - else if (interpreter_type & 2) - elf_entry = load_elf32_interp(&interp_elf_ex, - interpreter_inode, - &interp_load_addr); - - iput(interpreter_inode); - kfree(elf_interpreter); - - if (elf_entry == ~0UL) { - printk("Unable to load interpreter\n"); - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - } - } - - kfree(elf_phdata); - - if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); - current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); - - if (current->exec_domain && current->exec_domain->module) - __MOD_DEC_USE_COUNT(current->exec_domain->module); - if (current->binfmt && current->binfmt->module) - __MOD_DEC_USE_COUNT(current->binfmt->module); - current->exec_domain = lookup_exec_domain(current->personality); - current->binfmt = &elf32_format; - if (current->exec_domain && current->exec_domain->module) - __MOD_INC_USE_COUNT(current->exec_domain->module); - if (current->binfmt && current->binfmt->module) - __MOD_INC_USE_COUNT(current->binfmt->module); - -#ifndef VM_STACK_FLAGS - current->executable = bprm->inode; - bprm->inode->i_count++; -#endif -#ifdef LOW_ELF_STACK - current->start_stack = bprm->p = elf_stack - 4; -#endif - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; - current->flags &= ~PF_FORKNOEXEC; - bprm->p = (unsigned long) - create_elf32_tables((char *)bprm->p, - bprm->argc, - bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), - load_addr, - interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); - if (interpreter_type == INTERPRETER_AOUT) - current->mm->arg_start += strlen(passed_fileno) + 1; - current->mm->start_brk = current->mm->brk = elf_brk; - current->mm->end_code = end_code; - current->mm->start_code = start_code; - current->mm->end_data = end_data; - current->mm->start_stack = bprm->p; - - /* Calling set_brk effectively mmaps the pages that we need for the bss and break - sections */ - set_brk(elf_bss, elf_brk); - - padzero(elf_bss); - -#if 0 - printk("(start_brk) %x\n" , current->mm->start_brk); - printk("(end_code) %x\n" , current->mm->end_code); - printk("(start_code) %x\n" , current->mm->start_code); - printk("(end_data) %x\n" , current->mm->end_data); - printk("(start_stack) %x\n" , current->mm->start_stack); - printk("(brk) %x\n" , current->mm->brk); -#endif - - if ( current->personality == PER_SVR4 ) - { - /* Why this, you ask??? Well SVr4 maps page 0 as read-only, - and some applications "depend" upon this behavior. - Since we do not have the power to recompile these, we - emulate the SVr4 behavior. Sigh. */ - error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, 0); - } - -#ifdef ELF_PLAT_INIT - /* - * The ABI may specify that certain registers be set up in special - * ways (on i386 %edx is the address of a DT_FINI function, for - * example. This macro performs whatever initialization to - * the regs structure is required. - */ - ELF_PLAT_INIT(regs); -#endif - - - start_thread32(regs, elf_entry, bprm->p); - if (current->flags & PF_PTRACED) - send_sig(SIGTRAP, current, 0); - return 0; -} - -static int -load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs) -{ - int retval; - - MOD_INC_USE_COUNT; - retval = do_load_elf32_binary(bprm, regs); - MOD_DEC_USE_COUNT; - return retval; -} - -/* This is really simpleminded and specialized - we are loading an - a.out library that is given an ELF header. */ - -static inline int -do_load_elf32_library(int fd){ - struct file * file; - struct elfhdr elf_ex; - struct elf_phdr *elf_phdata = NULL; - struct inode * inode; - unsigned long len; - int elf_bss; - int retval; - unsigned long bss; - int error; - int i,j, k; - - len = 0; - file = current->files->fd[fd]; - inode = file->f_inode; - elf_bss = 0; - - if (!file || !file->f_op) - return -EACCES; - - /* seek to the beginning of the file */ - if (file->f_op->llseek) { - if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) - return -ENOEXEC; - } else - file->f_pos = 0; - - set_fs(KERNEL_DS); - error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)); - set_fs(USER_DS); - if (error != sizeof(elf_ex)) - return -ENOEXEC; - - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) - return -ENOEXEC; - - /* First of all, some simple consistency checks */ - if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - !elf_check_arch(elf_ex.e_machine) || - (!inode->i_op || !inode->i_op->default_file_ops->mmap)) - return -ENOEXEC; - - /* Now read in all of the header information */ - - if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) - return -ENOEXEC; - - elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); - if (elf_phdata == NULL) - return -ENOMEM; - - retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, - sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); - - j = 0; - for(i=0; i<elf_ex.e_phnum; i++) - if ((elf_phdata + i)->p_type == PT_LOAD) j++; - - if (j != 1) { - kfree(elf_phdata); - return -ENOEXEC; - } - - while(elf_phdata->p_type != PT_LOAD) elf_phdata++; - - /* Now use mmap to map the library into memory. */ - error = do_mmap(file, - ELF_PAGESTART(elf_phdata->p_vaddr), - (elf_phdata->p_filesz + - ELF_PAGEOFFSET(elf_phdata->p_vaddr)), - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, - (elf_phdata->p_offset - - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); - - k = elf_phdata->p_vaddr + elf_phdata->p_filesz; - if (k > elf_bss) elf_bss = k; - - if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { - kfree(elf_phdata); - return error; - } - - padzero(elf_bss); - - len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1); - bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; - if (bss > len) - do_mmap(NULL, len, bss-len, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - kfree(elf_phdata); - return 0; -} - -static int load_elf32_library(int fd) -{ - int retval; - - MOD_INC_USE_COUNT; - retval = do_load_elf32_library(fd); - MOD_DEC_USE_COUNT; - return retval; -} - -/* - * Note that some platforms still use traditional core dumps and not - * the ELF core dump. Each platform can select it as appropriate. - */ -#ifdef USE_ELF_CORE_DUMP - -/* - * ELF core dumper - * - * Modelled on fs/exec.c:aout_core_dump() - * Jeremy Fitzhardinge <jeremy@sw.oz.au> - */ -/* - * These are the only things you should do on a core-file: use only these - * functions to write out all the necessary info. - */ -static int dump_write(struct file *file, const void *addr, int nr) -{ - return file->f_op->write(file->f_inode, file, addr, nr) == nr; -} - -static int dump_seek(struct file *file, off_t off) -{ - if (file->f_op->llseek) { - if (file->f_op->llseek(file->f_inode, file, off, 0) != off) - return 0; - } else - file->f_pos = off; - return 1; -} - -/* - * Decide whether a segment is worth dumping; default is yes to be - * sure (missing info is worse than too much; etc). - * Personally I'd include everything, and use the coredump limit... - * - * I think we should skip something. But I am not sure how. H.J. - */ -static inline int maydump(struct vm_area_struct *vma) -{ - if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC))) - return 0; -#if 1 - if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN)) - return 1; - if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED)) - return 0; -#endif - return 1; -} - -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) - -/* An ELF note in memory */ -struct memelfnote -{ - const char *name; - int type; - unsigned int datasz; - void *data; -}; - -static int notesize(struct memelfnote *en) -{ - int sz; - - sz = sizeof(struct elf_note); - sz += roundup(strlen(en->name), 4); - sz += roundup(en->datasz, 4); - - return sz; -} - -/* #define DEBUG */ - -#define DUMP_WRITE(addr, nr) \ - do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) -#define DUMP_SEEK(off) \ - do { if (!dump_seek(file, (off))) return 0; } while(0) - -static int writenote(struct memelfnote *men, struct file *file) -{ - struct elf_note en; - - en.n_namesz = strlen(men->name); - en.n_descsz = men->datasz; - en.n_type = men->type; - - DUMP_WRITE(&en, sizeof(en)); - DUMP_WRITE(men->name, en.n_namesz); - /* XXX - cast from long long to long to avoid need for libgcc.a */ - DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ - DUMP_WRITE(men->data, men->datasz); - DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ - - return 1; -} -#undef DUMP_WRITE -#undef DUMP_SEEK - -#define DUMP_WRITE(addr, nr) \ - if (!dump_write(&file, (addr), (nr))) \ - goto close_coredump; -#define DUMP_SEEK(off) \ - if (!dump_seek(&file, (off))) \ - goto close_coredump; -/* - * Actual dumper - * - * This is a two-pass process; first we find the offsets of the bits, - * and then they are actually written out. If we run out of core limit - * we just truncate. - */ -static int elf32_core_dump(long signr, struct pt_regs * regs) -{ - int has_dumped = 0; - struct file file; - struct inode *inode; - unsigned short fs; - char corefile[6+sizeof(current->comm)]; - int segs; - int i; - size_t size; - struct vm_area_struct *vma; - struct elfhdr elf; - off_t offset = 0, dataoff; - int limit = current->rlim[RLIMIT_CORE].rlim_cur; - int numnote = 4; - struct memelfnote notes[4]; - struct elf_prstatus prstatus; /* NT_PRSTATUS */ - elf_fpregset_t fpu; /* NT_PRFPREG */ - struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - - if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) - return 0; - current->dumpable = 0; - -#ifndef CONFIG_BINFMT_ELF32 - MOD_INC_USE_COUNT; -#endif - - /* Count what's needed to dump, up to the limit of coredump size */ - segs = 0; - size = 0; - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { - if (maydump(vma)) - { - int sz = vma->vm_end-vma->vm_start; - - if (size+sz >= limit) - break; - else - size += sz; - } - - segs++; - } -#ifdef DEBUG - printk("elf_core_dump: %d segs taking %d bytes\n", segs, size); -#endif - - /* Set up header */ - memcpy(elf.e_ident, ELFMAG, SELFMAG); - elf.e_ident[EI_CLASS] = ELF_CLASS; - elf.e_ident[EI_DATA] = ELF_DATA; - elf.e_ident[EI_VERSION] = EV_CURRENT; - memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - - elf.e_type = ET_CORE; - elf.e_machine = ELF_ARCH; - elf.e_version = EV_CURRENT; - elf.e_entry = 0; - elf.e_phoff = sizeof(elf); - elf.e_shoff = 0; - elf.e_flags = 0; - elf.e_ehsize = sizeof(elf); - elf.e_phentsize = sizeof(struct elf_phdr); - elf.e_phnum = segs+1; /* Include notes */ - elf.e_shentsize = 0; - elf.e_shnum = 0; - elf.e_shstrndx = 0; - - fs = get_fs(); - set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { - inode = NULL; - goto end_coredump; - } - if (!S_ISREG(inode->i_mode)) - goto end_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto end_coredump; - file.f_mode = 3; - file.f_flags = 0; - file.f_count = 1; - file.f_inode = inode; - file.f_pos = 0; - file.f_reada = 0; - file.f_op = inode->i_op->default_file_ops; - if (file.f_op->open) - if (file.f_op->open(inode,&file)) - goto end_coredump; - if (!file.f_op->write) - goto close_coredump; - has_dumped = 1; - current->flags |= PF_DUMPCORE; - - DUMP_WRITE(&elf, sizeof(elf)); - offset += sizeof(elf); /* Elf header */ - offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ - - /* - * Set up the notes in similar form to SVR4 core dumps made - * with info from their /proc. - */ - memset(&psinfo, 0, sizeof(psinfo)); - memset(&prstatus, 0, sizeof(prstatus)); - - notes[0].name = "CORE"; - notes[0].type = NT_PRSTATUS; - notes[0].datasz = sizeof(prstatus); - notes[0].data = &prstatus; - prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; - prstatus.pr_sigpend = current->signal; - prstatus.pr_sighold = current->blocked; - psinfo.pr_pid = prstatus.pr_pid = current->pid; - psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; - psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; - psinfo.pr_sid = prstatus.pr_sid = current->session; - prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime); - prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime); - prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime); - prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime); - prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime); - prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime); - prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime); - prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime); - - /* - * This transfers the registers from regs into the standard - * coredump arrangement, whatever that is. - */ -#ifdef ELF_CORE_COPY_REGS - ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) -#else - if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) - { - printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n", - sizeof(elf_gregset_t), sizeof(struct pt_regs)); - } - else - *(struct pt_regs *)&prstatus.pr_reg = *regs; -#endif - - notes[1].name = "CORE"; - notes[1].type = NT_PRPSINFO; - notes[1].datasz = sizeof(psinfo); - notes[1].data = &psinfo; - psinfo.pr_state = current->state; - psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state]; - psinfo.pr_zomb = psinfo.pr_sname == 'Z'; - psinfo.pr_nice = current->priority-15; - psinfo.pr_flag = current->flags; - psinfo.pr_uid = current->uid; - psinfo.pr_gid = current->gid; - { - int i, len; - - set_fs(fs); - - len = current->mm->arg_end - current->mm->arg_start; - len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; - copy_from_user(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); - for(i = 0; i < len; i++) - if (psinfo.pr_psargs[i] == 0) - psinfo.pr_psargs[i] = ' '; - psinfo.pr_psargs[len] = 0; - - set_fs(KERNEL_DS); - } - strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); - - notes[2].name = "CORE"; - notes[2].type = NT_TASKSTRUCT; - notes[2].datasz = sizeof(*current); - notes[2].data = current; - - /* Try to dump the fpu. */ - prstatus.pr_fpvalid = dump_fpu (regs, &fpu); - if (!prstatus.pr_fpvalid) - { - numnote--; - } - else - { - notes[3].name = "CORE"; - notes[3].type = NT_PRFPREG; - notes[3].datasz = sizeof(fpu); - notes[3].data = &fpu; - } - - /* Write notes phdr entry */ - { - struct elf_phdr phdr; - int sz = 0; - - for(i = 0; i < numnote; i++) - sz += notesize(¬es[i]); - - phdr.p_type = PT_NOTE; - phdr.p_offset = offset; - phdr.p_vaddr = 0; - phdr.p_paddr = 0; - phdr.p_filesz = sz; - phdr.p_memsz = 0; - phdr.p_flags = 0; - phdr.p_align = 0; - - offset += phdr.p_filesz; - DUMP_WRITE(&phdr, sizeof(phdr)); - } - - /* Page-align dumped data */ - dataoff = offset = roundup(offset, PAGE_SIZE); - - /* Write program headers for segments dump */ - for(vma = current->mm->mmap, i = 0; - i < segs && vma != NULL; vma = vma->vm_next) { - struct elf_phdr phdr; - size_t sz; - - i++; - - sz = vma->vm_end - vma->vm_start; - - phdr.p_type = PT_LOAD; - phdr.p_offset = offset; - phdr.p_vaddr = vma->vm_start; - phdr.p_paddr = 0; - phdr.p_filesz = maydump(vma) ? sz : 0; - phdr.p_memsz = sz; - offset += phdr.p_filesz; - phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; - if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; - if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; - phdr.p_align = PAGE_SIZE; - - DUMP_WRITE(&phdr, sizeof(phdr)); - } - - for(i = 0; i < numnote; i++) - if (!writenote(¬es[i], &file)) - goto close_coredump; - - set_fs(fs); - - DUMP_SEEK(dataoff); - - for(i = 0, vma = current->mm->mmap; - i < segs && vma != NULL; - vma = vma->vm_next) { - unsigned long addr = vma->vm_start; - unsigned long len = vma->vm_end - vma->vm_start; - - i++; - if (!maydump(vma)) - continue; -#ifdef DEBUG - printk("elf_core_dump: writing %08lx %lx\n", addr, len); -#endif - DUMP_WRITE((void *)addr, len); - } - - if ((off_t) file.f_pos != offset) { - /* Sanity check */ - printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n", - (off_t) file.f_pos, offset); - } - - close_coredump: - if (file.f_op->release) - file.f_op->release(inode,&file); - - end_coredump: - set_fs(fs); - iput(inode); -#ifndef CONFIG_BINFMT_ELF32 - MOD_DEC_USE_COUNT; -#endif - return has_dumped; -} -#endif /* USE_ELF_CORE_DUMP */ - -__initfunc(int init_elf32_binfmt(void)) -{ - return register_binfmt(&elf32_format); -} - -#ifdef MODULE - -int init_module(void) -{ - /* Install the COFF, ELF and XOUT loaders. - * N.B. We *rely* on the table being the right size with the - * right number of free slots... - */ - return init_elf32_binfmt(); -} - - -void cleanup_module( void) -{ - /* Remove the COFF and ELF loaders. */ - unregister_binfmt(&elf32_format); -} -#endif diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index e9911daed..147b60c34 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $ +/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -27,15 +27,19 @@ #include <linux/nfs_fs.h> #include <linux/smb_fs.h> #include <linux/ncp_fs.h> +#include <linux/quota.h> #include <asm/types.h> #include <asm/poll.h> #include <asm/ipc.h> #include <asm/uaccess.h> -/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for. - * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will - * produce warnings */ +/* As gcc will warn about casting u32 to some ptr, we have to cast it to + * unsigned long first, and that's what is A() for. + * You just do (void *)A(x), instead of having to + * type (void *)((unsigned long)x) or instead of just (void *)x, which will + * produce warnings. + */ #define A(x) ((unsigned long)x) extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); @@ -138,6 +142,10 @@ extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags); extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags); extern asmlinkage int sys_socketcall(int call, unsigned long *args); extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp); +extern asmlinkage int sys_listen(int fd, int backlog); +extern asmlinkage int sys_socket(int family, int type, int protocol); +extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]); +extern asmlinkage int sys_shutdown(int fd, int how); asmlinkage int sys32_ioperm(u32 from, u32 num, int on) { @@ -157,6 +165,17 @@ struct ipc_perm32 unsigned short seq; }; +struct semid_ds32 { + struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t32 sem_otime; /* last semop time */ + __kernel_time_t32 sem_ctime; /* last change time */ + u32 sem_base; /* ptr to first semaphore in array */ + u32 sem_pending; /* pending operations to be processed */ + u32 sem_pending_last; /* last pending operation */ + u32 undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ +}; + struct msqid_ds32 { struct ipc_perm32 msg_perm; @@ -212,15 +231,62 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u err = sys_semget (first, second, third); goto out; case SEMCTL: { - /* XXX union semun32 to union semun64 and back conversion */ union semun fourth; + void *pad; + unsigned long old_fs; + struct semid_ds s; + err = -EINVAL; if (!ptr) goto out; err = -EFAULT; - if(get_user(fourth.__pad, (void **)A(ptr))) + if(get_user(pad, (void **)A(ptr))) goto out; + fourth.__pad = pad; + switch (third) { + case IPC_INFO: + case SEM_INFO: + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + case SETALL: + case IPC_RMID: + err = sys_semctl (first, second, third, fourth); + goto out; + case IPC_SET: + if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) || + __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) || + __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) { + err = -EFAULT; + goto out; + } + /* Fall through */ + case SEM_STAT: + case IPC_STAT: + fourth.__pad = &s; + break; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); err = sys_semctl (first, second, third, fourth); + set_fs (old_fs); + switch (third) { + case SEM_STAT: + case IPC_STAT: + if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) || + __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) || + __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) || + __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) || + __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) || + __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) || + __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) || + __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) || + __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) || + __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems))) + err = -EFAULT; + } goto out; } default: @@ -534,10 +600,50 @@ asmlinkage int sys32_rename(u32 oldname, u32 newname) return sys_rename((const char *)A(oldname), (const char *)A(newname)); } -/* XXX: Play with the addr, it will be ugly :(( */ +struct dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; + asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) { - return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); + int cmds = cmd >> SUBCMDSHIFT; + int err; + struct dqblk d; + unsigned long old_fs; + + switch (cmds) { + case Q_GETQUOTA: + break; + case Q_SETQUOTA: + case Q_SETUSE: + case Q_SETQLIM: + if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; + break; + default: + return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); + set_fs (old_fs); + if (cmds == Q_GETQUOTA) { + __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; + ((struct dqblk32 *)&d)->dqb_itime = i; + ((struct dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32))) + return -EFAULT; + } + return err; } static int put_statfs (u32 buf, struct statfs *s) @@ -1599,20 +1705,224 @@ asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen)); } -/* Continue here */ +struct msghdr32 { + u32 msg_name; + int msg_namelen; + u32 msg_iov; + __kernel_size_t32 msg_iovlen; + u32 msg_control; + __kernel_size_t32 msg_controllen; + unsigned msg_flags; +}; + +struct cmsghdr32 { + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; + unsigned char cmsg_data[0]; +}; + asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags) { - return sys_sendmsg(fd, (struct msghdr *)A(msg), flags); + struct msghdr m; + int count; + struct iovec *v; + struct iovec vf[UIO_FASTIOV]; + u32 i, vector; + long ret; + unsigned long old_fs; + + if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) || + __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) || + __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) || + __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) || + __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) || + __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) || + __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags))) + return -EFAULT; + + count = m.msg_iovlen; + if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; + if (count <= UIO_FASTIOV) + v = vf; + else { + lock_kernel (); + v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); + if (!v) { + ret = -ENOMEM; + goto out; + } + } + + for (i = 0; i < count; i++) { + if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || + __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { + ret = -EFAULT; + goto out; + } + } + + m.msg_iov = v; + + if (m.msg_controllen) { + /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */ + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + ret = sys_sendmsg(fd, &m, flags); + set_fs (old_fs); +out: + if (count > UIO_FASTIOV) { + kfree (v); + unlock_kernel (); + } + return ret; } asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags) { - return sys_recvmsg(fd, (struct msghdr *)A(msg), flags); + struct msghdr m; + int count; + struct iovec *v; + struct iovec vf[UIO_FASTIOV]; + u32 i, vector; + long ret; + unsigned long old_fs; + + if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) || + __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) || + __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) || + __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) || + __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) || + __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) || + __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags))) + return -EFAULT; + + count = m.msg_iovlen; + if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; + if (count <= UIO_FASTIOV) + v = vf; + else { + lock_kernel (); + v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); + if (!v) { + ret = -ENOMEM; + goto out; + } + } + + for (i = 0; i < count; i++) { + if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || + __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { + ret = -EFAULT; + goto out; + } + } + + m.msg_iov = v; + + if (m.msg_controllen) { + /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */ + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + ret = sys_recvmsg(fd, &m, flags); + set_fs (old_fs); + if (ret >= 0) { + /* XXX Handle msg_control stuff... */ + if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) || + __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen))) + return -EFAULT; + } +out: + if (count > UIO_FASTIOV) { + kfree (v); + unlock_kernel (); + } + return ret; } asmlinkage int sys32_socketcall(int call, u32 args) { - return sys_socketcall(call, (unsigned long *)A(args)); + static unsigned char nargs[18]={0,3,3,3,2,3,3,3, + 4,4,4,6,6,2,5,5,3,3}; + u32 a[6]; + u32 a0,a1; + int err = -EINVAL; + int i; + + lock_kernel(); + if(call<1||call>SYS_RECVMSG) + goto out; + err = -EFAULT; + + for (i = 0; i < nargs[call]; i++, args += sizeof (u32)) + if (get_user(a[i], (u32 *)A(args))) + goto out; + + a0=a[0]; + a1=a[1]; + + switch(call) + { + case SYS_SOCKET: + err = sys_socket(a0, a1, a[2]); + break; + case SYS_BIND: + err = sys32_bind(a0, a1, a[2]); + break; + case SYS_CONNECT: + err = sys32_connect(a0, a1, a[2]); + break; + case SYS_LISTEN: + err = sys_listen(a0, a1); + break; + case SYS_ACCEPT: + err = sys32_accept(a0, a1, a[2]); + break; + case SYS_GETSOCKNAME: + err = sys32_getsockname(a0, a1, a[2]); + break; + case SYS_GETPEERNAME: + err = sys32_getpeername(a0, a1, a[2]); + break; + case SYS_SOCKETPAIR: + err = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); + break; + case SYS_SEND: + err = sys32_send(a0, a1, a[2], a[3]); + break; + case SYS_SENDTO: + err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_RECV: + err = sys32_recv(a0, a1, a[2], a[3]); + break; + case SYS_RECVFROM: + err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_SHUTDOWN: + err = sys_shutdown(a0,a1); + break; + case SYS_SETSOCKOPT: + err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]); + break; + case SYS_GETSOCKOPT: + err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]); + break; + case SYS_SENDMSG: + err = sys32_sendmsg(a0, a1, a[2]); + break; + case SYS_RECVMSG: + err = sys32_recvmsg(a0, a1, a[2]); + break; + default: + err = -EINVAL; + break; + } +out: + unlock_kernel(); + return err; } extern void check_pending(int signum); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 48648c39d..c9774df06 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $ +/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $ * arch/sparc/kernel/traps.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,6 +22,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/unistd.h> +#include <asm/uaccess.h> /* #define TRAP_DEBUG */ @@ -42,6 +43,8 @@ void syscall_trace_entry(struct pt_regs *regs) void syscall_trace_exit(struct pt_regs *regs) { + printk("Syscall return check, reg dump.\n"); + show_regs(regs); } void sparc64_dtlb_fault_handler (void) @@ -116,25 +119,45 @@ void die_if_kernel(char *str, struct pt_regs *regs) show_regs(regs); printk("Instruction DUMP:"); instruction_dump ((unsigned int *) regs->tpc); + while(1) + barrier(); if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); } -void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long tstate) +void do_illegal_instruction(struct pt_regs *regs) { + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + lock_kernel(); if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); -#ifdef TRAP_DEBUG - printk("Ill instr. at pc=%016lx instruction is %08x\n", - regs->tpc, *(unsigned int *)regs->tpc); +#if 1 + { + unsigned int insn; + + printk("Ill instr. at pc=%016lx ", pc); + get_user(insn, ((unsigned int *)pc)); + printk("insn=[%08x]\n", insn); + } #endif current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); unlock_kernel(); + + while(1) + barrier(); +} + +void do_mna(struct pt_regs *regs) +{ + printk("AIEEE: do_mna at %016lx\n", regs->tpc); + show_regs(regs); + while(1) + barrier(); } void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index f22d85014..326382c3f 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $ +/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -13,7 +13,7 @@ tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception) tl0_resv009: BTRAP(0x9) tl0_iae: TRAP(do_iae) tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) -tl0_ill: TRAP(do_ill) +tl0_ill: TRAP(do_illegal_instruction) tl0_privop: TRAP(do_privop) tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17) tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) @@ -226,27 +226,3 @@ tl1_f4o: FILL_4_OTHER tl1_f5o: FILL_5_OTHER tl1_f6o: FILL_6_OTHER tl1_f7o: FILL_7_OTHER - -#if 0 -/* Unless we are going to have software trap insns in the kernel code, we - * don't need this. For now we just save 8KB. - */ - -#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7) - -tl1_sunos: BTRAPTL1(0x100) -tl1_bkpt: BREAKPOINT_TRAP -tl1_resv102: BTRAPTL1(0x102) -tl1_flushw: FLUSH_WINDOW_TRAP -tl1_resv104: BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106) -tl1_resv107: BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a) -tl1_resv10b: BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e) -tl1_resv10f: BTRAPTL1(0x10f) -tl1_resv110: BTRAPSTL1(0x110) BTRAPSTL1(0x118) -tl1_resv120: BTRAPSTL1(0x120) BTRAPSTL1(0x128) -tl1_resv130: BTRAPSTL1(0x130) BTRAPSTL1(0x138) -tl1_resv140: BTRAPSTL1(0x140) BTRAPSTL1(0x148) -tl1_resv150: BTRAPSTL1(0x150) BTRAPSTL1(0x158) -tl1_resv160: BTRAPSTL1(0x160) BTRAPSTL1(0x168) -tl1_resv170: BTRAPSTL1(0x170) BTRAPSTL1(0x178) -#endif diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S new file mode 100644 index 000000000..a8293c453 --- /dev/null +++ b/arch/sparc64/kernel/winfixup.S @@ -0,0 +1,101 @@ +/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $ + * + * winfixup.S: Handle cases where user stack pointer is found to be bogus. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <asm/asi.h> +#include <asm/head.h> +#include <asm/page.h> +#include <asm/ptrace.h> +#include <asm/processor.h> +#include <asm/asm_offsets.h> + + .text + .align 32 + + /* Here are the rules, pay attention. + * + * The kernel is disallowed from touching user space while + * the trap level is greater than zero, except for from within + * the window spill/fill handlers. This must be followed + * so that we can easily detect the case where we tried to + * spill/fill with a bogus (or unmapped) user stack pointer. + * + * These are layed out in a special way for cache reasons, + * don't touch... + */ + .globl winfix_trampoline, fill_fixup, spill_fixup +fill_fixup: + ba,pt %xcc, etrap + rd %pc, %g7 + mov %l5, %o4 + mov %l4, %o5 + srlx %l5, PAGE_SHIFT, %o3 + clr %o1 + sllx %o3, PAGE_SHIFT, %o3 + and %l4, 0x4, %o2 + + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap + nop +winfix_trampoline: + andn %g5, 0x7f, %g5 + add %g5, 0x7c, %g5 + wrpr %g5, %tnpc + done + +spill_fixup: + rd %pic, %g1 + ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2 + sll %g2, 3, %g5 + ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7 + add %g1, %g5, %g5 + andcc %g7, SPARC_FLAG_32BIT, %g0 + stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + sll %g2, 5, %g5 + + bne,pt %xcc, 1f + add %g1, %g5, %g5 + stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + + stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] + stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] + stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] + stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] + stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + + stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] + stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + b,a,pt %xcc, 2f + add %g2, 1, %g2 +1: + std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + + std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + add %g2, 1, %g2 +2: + stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] + rdpr %tstate, %g1 + nop + + andcc %g1, TSTATE_PRIV, %g0 + be,pn %xcc, fill_fixup + saved + retry diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index b3f06c18d..d0f023d1b 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $ +/* $Id: blockops.S,v 1.6 1997/05/18 04:16:49 davem Exp $ * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -31,37 +31,8 @@ .text .align 4 - .globl bzero_2page, bzero_1page -bzero_2page: - /* %o0 = buf */ - mov %o0, %o1 - wr %g0, ASI_BLK_P, %asi - mov 0x10, %g2 - - membar #Sync|#StoreLoad - - fzero %f48 - fzero %f50 - fzero %f52 - fzero %f54 - fzero %f56 - fzero %f58 - fzero %f60 - fzero %f62 -1: - BLAST_BLOCK(%o0, 0x000) - BLAST_BLOCK(%o0, 0x100) - BLAST_BLOCK(%o0, 0x200) - BLAST_BLOCK(%o0, 0x300) - subcc %g2, 1, %g2 - bne,pt %icc, 1b - add %o0, 0x400, %o0 - - membar #Sync|#LoadStore|#StoreStore - - retl - mov %o1, %o0 - +#if 0 + .globl bzero_1page bzero_1page: /* %o0 = buf */ mov %o0, %o1 @@ -89,9 +60,36 @@ bzero_1page: retl mov %o1, %o0 +#endif .globl __bfill64 __bfill64: +#if 1 + /* %o0 = buf, %o1 = 64-bit pattern */ +#define FILL_BLOCK(buf, offset) \ + stx %o1, [buf + offset + 0x38]; \ + stx %o1, [buf + offset + 0x30]; \ + stx %o1, [buf + offset + 0x28]; \ + stx %o1, [buf + offset + 0x20]; \ + stx %o1, [buf + offset + 0x18]; \ + stx %o1, [buf + offset + 0x10]; \ + stx %o1, [buf + offset + 0x08]; \ + stx %o1, [buf + offset + 0x00]; + + mov 0x20, %g2 +1: + FILL_BLOCK(%o0, 0x00) + FILL_BLOCK(%o0, 0x40) + FILL_BLOCK(%o0, 0x80) + FILL_BLOCK(%o0, 0xc0) + subcc %g2, 1, %g2 + bne,pt %icc, 1b + add %o0, 0x100, %o0 + retl + nop +#undef FILL_BLOCK + +#else /* %o0 = buf */ stx %o1, [%sp + 0x7ff + 128] wr %g0, ASI_BLK_P, %asi @@ -116,7 +114,9 @@ __bfill64: retl membar #Sync|#LoadStore|#StoreStore +#endif +#if 0 .globl __copy_1page __copy_1page: /* %o0 = dst, %o1 = src */ @@ -135,4 +135,4 @@ __copy_1page: retl membar #Sync|#LoadStore|#StoreStore - +#endif diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S index 8a06003ee..b63f0d6e8 100644 --- a/arch/sparc64/lib/checksum.S +++ b/arch/sparc64/lib/checksum.S @@ -44,13 +44,13 @@ csum_partial_end_cruft: andcc %o1, 8, %g0 ! check how much be,pn %icc, 1f ! caller asks %o1 & 0x8 - and %o1, 4, %g3 ! nope, check for word remaining + and %o1, 4, %g5 ! nope, check for word remaining ldd [%o0], %g2 ! load two addcc %g2, %o2, %o2 ! add first word to sum addccc %g3, %o2, %o2 ! add second word as well add %o0, 8, %o0 ! advance buf ptr addc %g0, %o2, %o2 ! add in final carry -1: brz,pn %g3, 1f ! nope, skip this code +1: brz,pn %g5, 1f ! nope, skip this code andcc %o1, 3, %o1 ! check for trailing bytes ld [%o0], %g2 ! load it addcc %g2, %o2, %o2 ! add to sum @@ -98,15 +98,17 @@ csum_partial: /* %o0=buf, %o1=len, %o2=sum */ srl %o2, 16, %g3 addc %g0, %g3, %g2 sll %o2, 16, %o2 + and %o0, 0x4, %g7 sll %g2, 16, %g3 srl %o2, 16, %o2 or %g3, %o2, %o2 1: brz,pn %g7, csum_partial_fix_aligned - nop + andn %o1, 0x7f, %o3 ld [%o0 + 0x00], %g2 sub %o1, 4, %o1 addcc %g2, %o2, %o2 add %o0, 4, %o0 + andn %o1, 0x7f, %o3 addc %g0, %o2, %o2 csum_partial_fix_aligned: brz,pt %o3, 3f ! none to do @@ -115,9 +117,9 @@ csum_partial_fix_aligned: CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5) CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5) CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5) - sub %o3, 128, %o3 ! detract from loop iters addc %g0, %o2, %o2 ! sink in final carry - brnz,pt %o3, 5b ! more to do + subcc %o3, 128, %o3 ! detract from loop iters + bne,pt %icc, 5b ! more to do add %o0, 128, %o0 ! advance buf ptr 3: brz,pn %g1, cpte ! nope andcc %o1, 0xf, %o3 ! anything left at all? @@ -125,7 +127,7 @@ csum_partial_fix_aligned: srl %g1, 1, %o4 ! compute offset sub %g7, %g1, %g7 ! adjust jmp ptr sub %g7, %o4, %g7 ! final jmp ptr adjust - jmp %g7 + (cpte - 8 - 10b) ! enter the table + jmp %g7 + (11f-10b) ! enter the table add %o0, %g1, %o0 ! advance buf ptr cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5) CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5) @@ -134,8 +136,8 @@ cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5) CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5) CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5) CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5) - addc %g0, %o2, %o2 ! fetch final carry - andcc %o1, 0xf, %g0 ! anything left at all? +11: addc %g0, %o2, %o2 ! fetch final carry + andcc %o1, 0xf, %o3 ! anything left at all? cpte: brnz,pn %o3, csum_partial_end_cruft ! yep, handle it sethi %uhi(KERNBASE), %g4 mov %o2, %o0 ! return computed csum @@ -322,13 +324,14 @@ __csum_partial_copy_sparc_generic: andcc %o0, 0x4, %g0 or %g3, %g7, %g7 1: be,pt %icc, 3f - andn %g1, 0x7f, %g0 + andn %g1, 0x7f, %g2 EX(ld [%o0 + 0x00], %g4, add %g1, 0,#) sub %g1, 4, %g1 EX2(st %g4, [%o1 + 0x00],#) add %o0, 4, %o0 addcc %g4, %g7, %g7 add %o1, 4, %o1 + andn %g1, 0x7f, %g2 addc %g0, %g7, %g7 cc_dword_aligned: 3: brz,pn %g2, 3f ! nope, less than one loop remains @@ -365,7 +368,7 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5) CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5) 12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling addc %g0, %g7, %g7 - andcc %o3, 0xf, %g0 ! check for low bits set + andcc %g1, 0xf, %o3 ! check for low bits set ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band sethi %uhi(KERNBASE), %g4 ! restore gfp mov %g7, %o0 ! give em the computed checksum @@ -555,7 +558,7 @@ __csum_partial_copy_end: add %i1, %i2, %i1 2: mov %i1, %o0 - wr %%g0, ASI_S, %%asi + wr %g0, ASI_S, %asi call __bzero_noasi mov %i3, %o1 1: diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S index ba26a1c01..50ec7bb3d 100644 --- a/arch/sparc64/lib/copy_from_user.S +++ b/arch/sparc64/lib/copy_from_user.S @@ -15,12 +15,16 @@ #include <asm/ptrace.h> #include <asm/asi.h> +#include <asm/head.h> + +#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4; #define EX(x,y,a,b,z) \ 98: x,y; \ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ -99: retl; \ +99: PRE_RETL \ + retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ .align 4; \ @@ -33,6 +37,7 @@ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ 99: c, d, e; \ + PRE_RETL \ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ @@ -234,6 +239,7 @@ copy_user_last7: EX(lduba [%o1] %asi, %g2, add %g0, 1,#) stb %g2, [%o0] 1: + PRE_RETL retl clr %o0 @@ -332,6 +338,7 @@ short_table_end: EX(lduba [%o1] %asi, %g2, add %g0, 1,#) stb %g2, [%o0] 1: + PRE_RETL retl clr %o0 @@ -355,6 +362,7 @@ short_aligned_end: .section .fixup,#alloc,#execinstr .align 4 97: + PRE_RETL retl mov %o2, %o0 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ @@ -388,6 +396,7 @@ short_aligned_end: 1: and %g1, 0x7f, %o0 add %o0, %g7, %o0 + PRE_RETL retl sub %o0, %g2, %o0 51: @@ -413,6 +422,7 @@ short_aligned_end: 3: sll %g2, 2, %g2 2: + PRE_RETL retl add %g1, %g2, %o0 52: @@ -431,6 +441,7 @@ short_aligned_end: add %g2, %g4, %g2 and %o2, 0xf, %o0 add %o0, %o3, %o0 + PRE_RETL retl sub %o0, %g2, %o0 54: @@ -441,6 +452,7 @@ short_aligned_end: and %o2, 0xf, %o2 sub %o3, %o1, %o3 sub %o2, %o4, %o2 + PRE_RETL retl add %o2, %o3, %o0 55: @@ -452,5 +464,6 @@ short_aligned_end: and %g2, 1, %g2 sll %o1, 1, %o1 add %o2, %g2, %o0 + PRE_RETL retl add %o0, %o1, %o0 diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S index 47a6bd337..733953743 100644 --- a/arch/sparc64/lib/copy_to_user.S +++ b/arch/sparc64/lib/copy_to_user.S @@ -14,13 +14,17 @@ */ #include <asm/ptrace.h> +#include <asm/head.h> #include <asm/asi.h> +#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4; + #define EX(x,y,a,b,z) \ 98: x,y; \ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ -99: retl; \ +99: PRE_RETL \ + retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ .align 4; \ @@ -33,6 +37,7 @@ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ 99: c, d, e; \ + PRE_RETL \ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ @@ -234,6 +239,7 @@ copy_user_last7: ldub [%o1], %g2 EX(stba %g2, [%o0] %asi, add %g0, 1,#) 1: + PRE_RETL retl clr %o0 @@ -332,6 +338,7 @@ short_table_end: ldub [%o1], %g2 EX(stba %g2, [%o0] %asi, add %g0, 1,#) 1: + PRE_RETL retl clr %o0 @@ -355,6 +362,7 @@ short_aligned_end: .section .fixup,#alloc,#execinstr .align 4 97: + PRE_RETL retl mov %o2, %o0 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ @@ -388,6 +396,7 @@ short_aligned_end: 1: and %g1, 0x7f, %o0 add %o0, %g7, %o0 + PRE_RETL retl sub %o0, %g2, %o0 51: @@ -413,6 +422,7 @@ short_aligned_end: 3: sll %g2, 2, %g2 2: + PRE_RETL retl add %g1, %g2, %o0 52: @@ -431,6 +441,7 @@ short_aligned_end: add %g2, %g4, %g2 and %o2, 0xf, %o0 add %o0, %o3, %o0 + PRE_RETL retl sub %o0, %g2, %o0 54: @@ -441,6 +452,7 @@ short_aligned_end: and %o2, 0xf, %o2 sub %o3, %o1, %o3 sub %o2, %o4, %o2 + PRE_RETL retl add %o2, %o3, %o0 55: @@ -452,5 +464,6 @@ short_aligned_end: and %g2, 1, %g2 sll %o1, 1, %o1 add %o2, %g2, %o0 + PRE_RETL retl add %o0, %o1, %o0 diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S index 24bea73fd..30beee3ff 100644 --- a/arch/sparc64/lib/strlen_user.S +++ b/arch/sparc64/lib/strlen_user.S @@ -8,6 +8,8 @@ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include <asm/asi.h> + #define LO_MAGIC 0x01010101 #define HI_MAGIC 0x80808080 @@ -19,21 +21,21 @@ __strlen_user: be,pt %icc, 9f sethi %hi(HI_MAGIC), %o4 10: - ldub [%o0], %o5 + lduba [%o0] ASI_S, %o5 brz,pn %o5, 21f add %o0, 1, %o0 andcc %o0, 3, %g0 be,pn %icc, 4f or %o4, %lo(HI_MAGIC), %o3 11: - ldub [%o0], %o5 + lduba [%o0] ASI_S, %o5 brz,pn %o5, 22f add %o0, 1, %o0 andcc %o0, 3, %g0 be,pt %icc, 5f sethi %hi(LO_MAGIC), %o4 12: - ldub [%o0], %o5 + lduba [%o0] ASI_S, %o5 brz,pn %o5, 23f add %o0, 1, %o0 ba,pt %icc, 13f @@ -45,7 +47,7 @@ __strlen_user: 5: or %o4, %lo(LO_MAGIC), %o2 13: - ld [%o0], %o5 + lda [%o0] ASI_S, %o5 2: sub %o5, %o2, %o4 andcc %o4, %o3, %g0 @@ -68,7 +70,7 @@ __strlen_user: andcc %o5, 0xff, %g0 bne,a,pt %icc, 2b 14: - ld [%o0], %o5 + lda [%o0] ASI_S, %o5 add %o4, 1, %o4 1: retl diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S index 05a48eb5a..e0fb0f09b 100644 --- a/arch/sparc64/lib/strncpy_from_user.S +++ b/arch/sparc64/lib/strncpy_from_user.S @@ -24,14 +24,14 @@ __strncpy_from_user: sub %g0, %o2, %o3 add %o0, %o2, %o0 10: - ldub [%o1 + %o3], %o4 + lduba [%o1 + %o3] ASI_S, %o4 1: brz,pn %o4, 2f stb %o4, [%o0 + %o3] addcc %o3, 1, %o3 bne,pt %xcc, 1b 11: - ldub [%o1 + %o3], %o4 + lduba [%o1 + %o3] ASI_S, %o4 retl mov %o2, %o0 2: diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c index 4e7de16fb..0272b09c2 100644 --- a/arch/sparc64/mm/asyncd.c +++ b/arch/sparc64/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.1 1996/12/26 10:24:24 davem Exp $ +/* $Id: asyncd.c,v 1.2 1997/05/15 21:14:32 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -153,7 +153,7 @@ static int fault_in_page(int taskid, if(!pte) goto no_memory; if(!pte_present(*pte)) { - do_no_page(tsk, vma, address, write); + handle_mm_fault(tsk, vma, address, write); goto finish_up; } set_pte(pte, pte_mkyoung(*pte)); @@ -165,12 +165,11 @@ static int fault_in_page(int taskid, flush_tlb_page(vma, address); goto finish_up; } - do_wp_page(tsk, vma, address, write); + handle_mm_fault(tsk, vma, address, write); /* Fall through for do_wp_page */ finish_up: stats.success++; - update_mmu_cache(vma, address, *pte); return 0; no_memory: diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 0dd118c8e..dc28ac339 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.4 1997/03/11 17:37:07 jj Exp $ +/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -134,8 +134,11 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, return 0; } +/* #define FAULT_TRACER */ + asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write, - unsigned long address) + unsigned long address, unsigned long tag, + unsigned long sfsr) { struct vm_area_struct *vma; struct task_struct *tsk = current; @@ -143,7 +146,19 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write unsigned long fixup; unsigned long g2; int from_user = !(regs->tstate & TSTATE_PRIV); - +#ifdef FAULT_TRACER + static unsigned long last_addr = 0; + static int rcnt = 0; + + printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]" + "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr); + if(address == last_addr && rcnt++ > 5) { + printk("Wheee lotsa bogus faults, something wrong, spinning\n"); + while(1) + barrier(); + } + last_addr = address; +#endif lock_kernel (); down(&mm->mmap_sem); vma = find_vma(mm, address); @@ -168,7 +183,7 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(vma, address, write); + handle_mm_fault(current, vma, address, write); up(&mm->mmap_sem); goto out; /* diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 57ca5eb92..cf378a266 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $ +/* $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -457,16 +457,18 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr) pte_clear(ptep); } -#ifdef DEBUG_MMU void sparc_ultra_dump_itlb(void) { int slot; - prom_printf ("Contents of itlb:\n"); - for (slot = 0; slot < 64; slot+=2) { - prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + printk ("Contents of itlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), - slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1)); + slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1), + slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); } } @@ -474,14 +476,16 @@ void sparc_ultra_dump_dtlb(void) { int slot; - prom_printf ("Contents of dtlb:\n"); - for (slot = 0; slot < 64; slot+=2) { - prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + printk ("Contents of dtlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), - slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1)); + slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), + slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); } } -#endif /* paging_init() sets up the page tables */ @@ -643,7 +647,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) high_memory = (void *) end_mem; start_mem = PAGE_ALIGN(start_mem); - num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT; + num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT; addr = PAGE_OFFSET; while(addr < start_mem) { @@ -694,6 +698,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) min_free_pages = 16; free_pages_low = min_free_pages + (min_free_pages >> 1); free_pages_high = min_free_pages + min_free_pages; + +#if 0 + printk("Testing fault handling...\n"); + *(char *)0x00000deadbef0000UL = 0; +#endif } void free_initmem (void) @@ -702,9 +711,14 @@ void free_initmem (void) addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); - free_page(addr); + unsigned long page = addr; + + if(page < ((unsigned long)__va(phys_base))) + page += phys_base; + + mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved); + atomic_set(&mem_map[MAP_NR(page)].count, 1); + free_page(page); } } |