summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-12-28 04:06:37 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2002-12-28 04:06:37 -0800
commitfb7d196b9a65a800e5d841c2543267383e6bf3cd (patch)
tree7c2b2ab6d9439ce64384f7542fd5e2da817ea306
parent339d617ff03e2cc4326526f6ff395947b41d920b (diff)
parent8b3c4cbfc0e727c76b53e55f22610d814e44dc97 (diff)
Merge
-rw-r--r--Documentation/Changes13
-rw-r--r--Documentation/kbuild/makefiles.txt2
-rw-r--r--Documentation/modules.txt14
-rw-r--r--Documentation/networking/z8530drv.txt2
-rw-r--r--Documentation/sound/oss/Introduction6
-rw-r--r--Documentation/sysctl/kernel.txt4
-rw-r--r--Documentation/uml/UserModeLinux-HOWTO.txt4686
-rw-r--r--Documentation/usb/hotplug.txt14
-rw-r--r--Documentation/video4linux/README.cpia6
-rw-r--r--arch/i386/Kconfig23
-rw-r--r--arch/i386/Makefile1
-rw-r--r--arch/i386/kernel/apic.c3
-rw-r--r--arch/i386/kernel/cpu/mcheck/k7.c5
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c2
-rw-r--r--arch/i386/kernel/nmi.c4
-rw-r--r--arch/i386/oprofile/nmi_int.c2
-rw-r--r--arch/i386/oprofile/op_model_athlon.c2
-rw-r--r--arch/i386/oprofile/op_model_ppro.c2
-rw-r--r--arch/i386/oprofile/timer_int.c2
-rw-r--r--arch/m68k/Kconfig44
-rw-r--r--arch/m68k/Makefile1
-rw-r--r--arch/m68k/amiga/cia.c1
-rw-r--r--arch/m68k/amiga/config.c1
-rw-r--r--arch/m68k/apollo/config.c1
-rw-r--r--arch/m68k/atari/ataints.c24
-rw-r--r--arch/m68k/atari/atasound.c5
-rw-r--r--arch/m68k/atari/config.c7
-rw-r--r--arch/m68k/atari/stdma.c17
-rw-r--r--arch/m68k/atari/stram.c4
-rw-r--r--arch/m68k/atari/time.c5
-rw-r--r--arch/m68k/bvme6000/config.c6
-rw-r--r--arch/m68k/bvme6000/rtc.c13
-rw-r--r--arch/m68k/kernel/entry.S6
-rw-r--r--arch/m68k/kernel/head.S60
-rw-r--r--arch/m68k/kernel/m68k_defs.c14
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c1
-rw-r--r--arch/m68k/kernel/process.c13
-rw-r--r--arch/m68k/kernel/setup.c3
-rw-r--r--arch/m68k/kernel/signal.c2
-rw-r--r--arch/m68k/kernel/traps.c27
-rw-r--r--arch/m68k/mac/config.c38
-rw-r--r--arch/m68k/mac/iop.c10
-rw-r--r--arch/m68k/mac/macboing.c15
-rw-r--r--arch/m68k/mac/macints.c28
-rw-r--r--arch/m68k/mac/misc.c20
-rw-r--r--arch/m68k/mac/via.c74
-rw-r--r--arch/m68k/mm/extable.c26
-rw-r--r--arch/m68k/mm/sun3mmu.c2
-rw-r--r--arch/m68k/mvme147/config.c8
-rw-r--r--arch/m68k/mvme16x/config.c1
-rw-r--r--arch/m68k/mvme16x/rtc.c13
-rw-r--r--arch/m68k/q40/q40ints.c3
-rw-r--r--arch/m68k/sun3/config.c5
-rw-r--r--arch/m68k/sun3/dvma.c12
-rw-r--r--arch/m68k/sun3/intersil.c4
-rw-r--r--arch/m68k/sun3/prom/console.c16
-rw-r--r--arch/m68k/sun3/prom/misc.c8
-rw-r--r--arch/m68k/sun3/sbus.c9
-rw-r--r--arch/m68k/sun3x/dvma.c7
-rw-r--r--arch/m68k/sun3x/prom.c8
-rw-r--r--arch/m68k/sun3x/time.c4
-rw-r--r--arch/m68k/vmlinux-std.lds7
-rw-r--r--arch/m68k/vmlinux-sun3.lds7
-rw-r--r--arch/um/Kconfig93
-rw-r--r--arch/um/Kconfig_block34
-rw-r--r--arch/um/Kconfig_char76
-rw-r--r--arch/um/Kconfig_net147
-rw-r--r--arch/um/Makefile78
-rw-r--r--arch/um/Makefile-i3864
-rw-r--r--arch/um/boot/Makefile3
-rw-r--r--arch/um/config_block.in16
-rw-r--r--arch/um/config_char.in37
-rw-r--r--arch/um/config_net.in46
-rw-r--r--arch/um/config_scsi.in30
-rw-r--r--arch/um/drivers/Makefile24
-rw-r--r--arch/um/drivers/chan_kern.c66
-rw-r--r--arch/um/drivers/chan_user.c33
-rw-r--r--arch/um/drivers/fd.c8
-rw-r--r--arch/um/drivers/line.c108
-rw-r--r--arch/um/drivers/mcast_kern.c4
-rw-r--r--arch/um/drivers/mconsole_kern.c62
-rw-r--r--arch/um/drivers/net_kern.c111
-rw-r--r--arch/um/drivers/null.c5
-rw-r--r--arch/um/drivers/port_kern.c25
-rw-r--r--arch/um/drivers/port_user.c47
-rw-r--r--arch/um/drivers/pty.c19
-rw-r--r--arch/um/drivers/slip.h10
-rw-r--r--arch/um/drivers/slip_kern.c9
-rw-r--r--arch/um/drivers/slip_proto.h93
-rw-r--r--arch/um/drivers/slip_user.c106
-rw-r--r--arch/um/drivers/slirp.h51
-rw-r--r--arch/um/drivers/slirp_kern.c132
-rw-r--r--arch/um/drivers/slirp_user.c202
-rw-r--r--arch/um/drivers/ssl.c36
-rw-r--r--arch/um/drivers/stdio_console.c32
-rw-r--r--arch/um/drivers/tty.c8
-rw-r--r--arch/um/drivers/ubd_kern.c48
-rw-r--r--arch/um/drivers/ubd_user.c2
-rw-r--r--arch/um/drivers/xterm.c7
-rw-r--r--arch/um/drivers/xterm_kern.c6
-rw-r--r--arch/um/include/chan_kern.h3
-rw-r--r--arch/um/include/chan_user.h4
-rw-r--r--arch/um/include/choose-mode.h35
-rw-r--r--arch/um/include/frame.h18
-rw-r--r--arch/um/include/kern.h2
-rw-r--r--arch/um/include/kern_util.h28
-rw-r--r--arch/um/include/line.h11
-rw-r--r--arch/um/include/mconsole_kern.h16
-rw-r--r--arch/um/include/mem.h1
-rw-r--r--arch/um/include/mem_user.h12
-rw-r--r--arch/um/include/mode.h30
-rw-r--r--arch/um/include/mode_kern.h30
-rw-r--r--arch/um/include/net_kern.h5
-rw-r--r--arch/um/include/net_user.h5
-rw-r--r--arch/um/include/os.h8
-rw-r--r--arch/um/include/sigcontext.h2
-rw-r--r--arch/um/include/syscall_user.h13
-rw-r--r--arch/um/include/sysdep-i386/checksum.h217
-rw-r--r--arch/um/include/sysdep-i386/frame_kern.h9
-rw-r--r--arch/um/include/sysdep-i386/ptrace.h111
-rw-r--r--arch/um/include/sysdep-i386/sigcontext.h33
-rw-r--r--arch/um/include/time_user.h2
-rw-r--r--arch/um/include/um_mmu.h40
-rw-r--r--arch/um/include/um_uaccess.h73
-rw-r--r--arch/um/include/user_util.h26
-rw-r--r--arch/um/kernel/Makefile56
-rw-r--r--arch/um/kernel/checksum.c42
-rw-r--r--arch/um/kernel/exec_kern.c64
-rw-r--r--arch/um/kernel/exitcode.c2
-rw-r--r--arch/um/kernel/frame.c202
-rw-r--r--arch/um/kernel/frame_kern.c85
-rw-r--r--arch/um/kernel/helper.c10
-rw-r--r--arch/um/kernel/init_task.c2
-rw-r--r--arch/um/kernel/irq_user.c4
-rw-r--r--arch/um/kernel/ksyms.c17
-rw-r--r--arch/um/kernel/mem.c71
-rw-r--r--arch/um/kernel/mem_user.c44
-rw-r--r--arch/um/kernel/process.c136
-rw-r--r--arch/um/kernel/process_kern.c477
-rw-r--r--arch/um/kernel/ptrace.c61
-rw-r--r--arch/um/kernel/reboot.c25
-rw-r--r--arch/um/kernel/sigio_user.c13
-rw-r--r--arch/um/kernel/signal_kern.c27
-rw-r--r--arch/um/kernel/signal_user.c9
-rw-r--r--arch/um/kernel/skas/Makefile24
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/exec_user.c61
-rw-r--r--arch/um/kernel/skas/include/mmu.h27
-rw-r--r--arch/um/kernel/skas/include/mode.h34
-rw-r--r--arch/um/kernel/skas/include/mode_kern.h52
-rw-r--r--arch/um/kernel/skas/include/proc_mm.h55
-rw-r--r--arch/um/kernel/skas/include/ptrace-skas.h57
-rw-r--r--arch/um/kernel/skas/include/skas.h49
-rw-r--r--arch/um/kernel/skas/include/skas_ptrace.h36
-rw-r--r--arch/um/kernel/skas/include/uaccess.h236
-rw-r--r--arch/um/kernel/skas/mem.c35
-rw-r--r--arch/um/kernel/skas/mem_user.c95
-rw-r--r--arch/um/kernel/skas/mmu.c46
-rw-r--r--arch/um/kernel/skas/process.c386
-rw-r--r--arch/um/kernel/skas/process_kern.c195
-rw-r--r--arch/um/kernel/skas/sys-i386/Makefile14
-rw-r--r--arch/um/kernel/skas/sys-i386/sigcontext.c114
-rw-r--r--arch/um/kernel/skas/syscall_kern.c42
-rw-r--r--arch/um/kernel/skas/syscall_user.c47
-rw-r--r--arch/um/kernel/skas/time.c30
-rw-r--r--arch/um/kernel/skas/tlb.c156
-rw-r--r--arch/um/kernel/skas/trap_user.c66
-rw-r--r--arch/um/kernel/skas/util/Makefile10
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs.c50
-rw-r--r--arch/um/kernel/smp.c12
-rw-r--r--arch/um/kernel/sys_call_table.c19
-rw-r--r--arch/um/kernel/syscall_kern.c132
-rw-r--r--arch/um/kernel/syscall_user.c79
-rw-r--r--arch/um/kernel/sysrq.c8
-rw-r--r--arch/um/kernel/tempfile.c3
-rw-r--r--arch/um/kernel/time.c22
-rw-r--r--arch/um/kernel/time_kern.c3
-rw-r--r--arch/um/kernel/tlb.c219
-rw-r--r--arch/um/kernel/trap_kern.c361
-rw-r--r--arch/um/kernel/trap_user.c492
-rw-r--r--arch/um/kernel/tt/Makefile20
-rw-r--r--arch/um/kernel/tt/exec_kern.c84
-rw-r--r--arch/um/kernel/tt/exec_user.c (renamed from arch/um/kernel/exec_user.c)0
-rw-r--r--arch/um/kernel/tt/gdb.c278
-rw-r--r--arch/um/kernel/tt/gdb_kern.c40
-rw-r--r--arch/um/kernel/tt/include/debug.h (renamed from arch/um/include/debug.h)3
-rw-r--r--arch/um/kernel/tt/include/mmu.h (renamed from arch/um/kernel/setup.c)11
-rw-r--r--arch/um/kernel/tt/include/mode.h35
-rw-r--r--arch/um/kernel/tt/include/mode_kern.h53
-rw-r--r--arch/um/kernel/tt/include/ptrace-tt.h26
-rw-r--r--arch/um/kernel/tt/include/tt.h45
-rw-r--r--arch/um/kernel/tt/include/uaccess.h119
-rw-r--r--arch/um/kernel/tt/ksyms.c28
-rw-r--r--arch/um/kernel/tt/mem.c77
-rw-r--r--arch/um/kernel/tt/process_kern.c513
-rw-r--r--arch/um/kernel/tt/ptproxy/Makefile13
-rw-r--r--arch/um/kernel/tt/ptproxy/proxy.c (renamed from arch/um/ptproxy/proxy.c)0
-rw-r--r--arch/um/kernel/tt/ptproxy/ptproxy.h (renamed from arch/um/ptproxy/ptproxy.h)0
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c (renamed from arch/um/ptproxy/ptrace.c)1
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c (renamed from arch/um/ptproxy/sysdep.c)0
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.h (renamed from arch/um/ptproxy/sysdep.h)0
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.c (renamed from arch/um/ptproxy/wait.c)0
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.h (renamed from arch/um/ptproxy/wait.h)0
-rw-r--r--arch/um/kernel/tt/sys-i386/Makefile14
-rw-r--r--arch/um/kernel/tt/sys-i386/sigcontext.c59
-rw-r--r--arch/um/kernel/tt/syscall_kern.c140
-rw-r--r--arch/um/kernel/tt/syscall_user.c90
-rw-r--r--arch/um/kernel/tt/time.c28
-rw-r--r--arch/um/kernel/tt/tlb.c226
-rw-r--r--arch/um/kernel/tt/tracer.c466
-rw-r--r--arch/um/kernel/tt/trap_user.c58
-rw-r--r--arch/um/kernel/tt/uaccess_user.c (renamed from arch/um/kernel/uaccess_user.c)0
-rw-r--r--arch/um/kernel/tty_log.c2
-rw-r--r--arch/um/kernel/um_arch.c119
-rw-r--r--arch/um/kernel/umid.c6
-rw-r--r--arch/um/main.c64
-rw-r--r--arch/um/os-Linux/Makefile6
-rw-r--r--arch/um/os-Linux/drivers/Makefile3
-rw-r--r--arch/um/os-Linux/file.c4
-rw-r--r--arch/um/os-Linux/process.c42
-rw-r--r--arch/um/os-Linux/tty.c2
-rw-r--r--arch/um/ptproxy/Makefile10
-rw-r--r--arch/um/sys-i386/Makefile32
-rw-r--r--arch/um/sys-i386/checksum.S460
-rw-r--r--arch/um/sys-i386/ksyms.c3
-rw-r--r--arch/um/sys-i386/ldt.c69
-rw-r--r--arch/um/sys-i386/ptrace.c57
-rw-r--r--arch/um/sys-i386/ptrace_user.c2
-rw-r--r--arch/um/sys-i386/sigcontext.c39
-rw-r--r--arch/um/sys-i386/util/mk_thread_kern.c16
-rw-r--r--arch/um/sys-i386/util/mk_thread_user.c32
-rw-r--r--arch/um/uml.lds.S12
-rw-r--r--arch/um/util/Makefile11
-rw-r--r--arch/um/util/mk_constants_kern.c24
-rw-r--r--arch/um/util/mk_constants_user.c28
-rw-r--r--arch/x86_64/Kconfig2
-rw-r--r--arch/x86_64/Makefile2
-rw-r--r--arch/x86_64/boot/Makefile1
-rw-r--r--arch/x86_64/defconfig6
-rw-r--r--arch/x86_64/ia32/Makefile2
-rw-r--r--arch/x86_64/ia32/fpu32.c12
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c6
-rw-r--r--arch/x86_64/ia32/ia32entry.S48
-rw-r--r--arch/x86_64/ia32/sys_ia32.c5
-rw-r--r--arch/x86_64/ia32/syscall32.c64
-rw-r--r--arch/x86_64/kernel/Makefile4
-rw-r--r--arch/x86_64/kernel/apic.c1
-rw-r--r--arch/x86_64/kernel/signal.c5
-rw-r--r--arch/x86_64/kernel/time.c13
-rw-r--r--arch/x86_64/kernel/traps.c5
-rw-r--r--arch/x86_64/kernel/x8664_ksyms.c10
-rw-r--r--arch/x86_64/mm/fault.c14
-rw-r--r--arch/x86_64/oprofile/Kconfig23
-rw-r--r--arch/x86_64/oprofile/Makefile33
-rw-r--r--drivers/block/acsi.c5
-rw-r--r--drivers/block/acsi_slm.c20
-rw-r--r--drivers/block/amiflop.c33
-rw-r--r--drivers/block/ataflop.c69
-rw-r--r--drivers/block/swim_iop.c25
-rw-r--r--drivers/block/z2ram.c2
-rw-r--r--drivers/char/amiserial.c124
-rw-r--r--drivers/char/ser_a2232.c25
-rw-r--r--drivers/char/serial167.c144
-rw-r--r--drivers/char/vme_scc.c60
-rw-r--r--drivers/ide/ide-io.c4
-rw-r--r--drivers/ide/ide.c12
-rw-r--r--drivers/input/joystick/amijoy.c1
-rw-r--r--drivers/input/keyboard/amikbd.c1
-rw-r--r--drivers/input/mouse/amimouse.c1
-rw-r--r--drivers/input/serio/q40kbd.c4
-rw-r--r--drivers/macintosh/adb-iop.c20
-rw-r--r--drivers/macintosh/via-cuda.c1
-rw-r--r--drivers/macintosh/via-macii.c36
-rw-r--r--drivers/macintosh/via-maciisi.c22
-rw-r--r--drivers/macintosh/via-pmu68k.c20
-rw-r--r--drivers/net/a2065.c7
-rw-r--r--drivers/net/ariadne.c10
-rw-r--r--drivers/net/atari_bionet.c24
-rw-r--r--drivers/net/atari_pamsnet.c14
-rw-r--r--drivers/net/atarilance.c5
-rw-r--r--drivers/net/mac8390.c4
-rw-r--r--drivers/net/mac89x0.c20
-rw-r--r--drivers/net/macmace.c5
-rw-r--r--drivers/net/macsonic.c5
-rw-r--r--drivers/net/sun3_82586.c5
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/nubus/nubus.c5
-rw-r--r--drivers/parport/parport_amiga.c1
-rw-r--r--drivers/parport/parport_atari.c36
-rw-r--r--drivers/parport/parport_mfc3.c1
-rw-r--r--drivers/pcmcia/yenta.c1
-rw-r--r--drivers/scsi/53c7xx.c163
-rw-r--r--drivers/scsi/NCR5380.c3
-rw-r--r--drivers/scsi/NCR53C9x.c57
-rw-r--r--drivers/scsi/NCR53C9x.h8
-rw-r--r--drivers/scsi/a2091.c17
-rw-r--r--drivers/scsi/a2091.h13
-rw-r--r--drivers/scsi/a3000.c17
-rw-r--r--drivers/scsi/a3000.h14
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx2
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx2
-rw-r--r--drivers/scsi/amiga7xx.c15
-rw-r--r--drivers/scsi/amiga7xx.h11
-rw-r--r--drivers/scsi/atari_NCR5380.c95
-rw-r--r--drivers/scsi/atari_scsi.c34
-rw-r--r--drivers/scsi/atari_scsi.h14
-rw-r--r--drivers/scsi/blz1230.c65
-rw-r--r--drivers/scsi/blz1230.h75
-rw-r--r--drivers/scsi/blz2060.c60
-rw-r--r--drivers/scsi/blz2060.h70
-rw-r--r--drivers/scsi/bvme6000.c15
-rw-r--r--drivers/scsi/bvme6000.h11
-rw-r--r--drivers/scsi/cyberstorm.c65
-rw-r--r--drivers/scsi/cyberstorm.h73
-rw-r--r--drivers/scsi/cyberstormII.c53
-rw-r--r--drivers/scsi/cyberstormII.h60
-rw-r--r--drivers/scsi/dec_esp.c26
-rw-r--r--drivers/scsi/dec_esp.h45
-rw-r--r--drivers/scsi/fastlane.c60
-rw-r--r--drivers/scsi/fastlane.h65
-rw-r--r--drivers/scsi/gvp11.c17
-rw-r--r--drivers/scsi/gvp11.h16
-rw-r--r--drivers/scsi/jazz_esp.c19
-rw-r--r--drivers/scsi/jazz_esp.h39
-rw-r--r--drivers/scsi/mac_NCR5380.c105
-rw-r--r--drivers/scsi/mac_esp.c21
-rw-r--r--drivers/scsi/mac_esp.h40
-rw-r--r--drivers/scsi/mac_scsi.c14
-rw-r--r--drivers/scsi/mca_53c9x.c43
-rw-r--r--drivers/scsi/mca_53c9x.h66
-rw-r--r--drivers/scsi/mvme147.c17
-rw-r--r--drivers/scsi/mvme147.h18
-rw-r--r--drivers/scsi/mvme16x.c15
-rw-r--r--drivers/scsi/mvme16x.h11
-rw-r--r--drivers/scsi/oktagon_esp.c34
-rw-r--r--drivers/scsi/oktagon_esp.h57
-rw-r--r--drivers/scsi/sun3_NCR5380.c88
-rw-r--r--drivers/scsi/sun3_scsi.c21
-rw-r--r--drivers/scsi/sun3_scsi.h16
-rw-r--r--drivers/scsi/sun3_scsi_vme.c21
-rw-r--r--drivers/scsi/sun3x_esp.c20
-rw-r--r--drivers/scsi/sun3x_esp.h39
-rw-r--r--drivers/scsi/wd33c93.c67
-rw-r--r--drivers/scsi/wd33c93.h1
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/atafb.c6
-rw-r--r--drivers/video/cfbcopyarea.c2
-rw-r--r--drivers/video/cfbimgblt.c94
-rw-r--r--drivers/video/console/fbcon.c1
-rw-r--r--drivers/video/console/font.h16
-rw-r--r--drivers/video/tgafb.c1520
-rw-r--r--include/asm-i386/bugs.h5
-rw-r--r--include/asm-i386/cpufeature.h1
-rw-r--r--include/asm-i386/processor.h2
-rw-r--r--include/asm-i386/system.h6
-rw-r--r--include/asm-m68k/ide.h14
-rw-r--r--include/asm-m68k/macintosh.h7
-rw-r--r--include/asm-m68k/mman.h2
-rw-r--r--include/asm-m68k/module.h13
-rw-r--r--include/asm-m68k/sbus.h2
-rw-r--r--include/asm-m68k/system.h2
-rw-r--r--include/asm-m68k/thread_info.h4
-rw-r--r--include/asm-um/a.out.h8
-rw-r--r--include/asm-um/checksum.h2
-rw-r--r--include/asm-um/mmu.h18
-rw-r--r--include/asm-um/mmu_context.h51
-rw-r--r--include/asm-um/page.h2
-rw-r--r--include/asm-um/pgtable.h6
-rw-r--r--include/asm-um/processor-generic.h39
-rw-r--r--include/asm-um/ptrace-generic.h2
-rw-r--r--include/asm-um/system-generic.h1
-rw-r--r--include/asm-um/thread_info.h10
-rw-r--r--include/asm-um/uaccess.h100
-rw-r--r--include/asm-x86_64/bitops.h2
-rw-r--r--include/asm-x86_64/desc.h2
-rw-r--r--include/asm-x86_64/dma-mapping.h1
-rw-r--r--include/asm-x86_64/hw_irq.h15
-rw-r--r--include/asm-x86_64/ia32.h2
-rw-r--r--include/asm-x86_64/io_apic.h1
-rw-r--r--include/asm-x86_64/processor.h2
-rw-r--r--include/asm-x86_64/proto.h2
-rw-r--r--include/asm-x86_64/spinlock.h2
-rw-r--r--include/asm-x86_64/system.h7
-rw-r--r--include/asm-x86_64/thread_info.h2
-rw-r--r--include/asm-x86_64/uaccess.h106
-rw-r--r--include/linux/fb.h2
-rw-r--r--include/linux/ide.h4
-rw-r--r--include/linux/nubus.h51
-rw-r--r--include/video/font.h24
-rw-r--r--include/video/tgafb.h (renamed from drivers/video/tgafb.h)149
-rw-r--r--kernel/printk.c2
-rw-r--r--scripts/ver_linux2
392 files changed, 15489 insertions, 5923 deletions
diff --git a/Documentation/Changes b/Documentation/Changes
index a57fca2015c2..8df1075acfe8 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -52,7 +52,7 @@ o Gnu C 2.95.3 # gcc --version
o Gnu make 3.78 # make --version
o binutils 2.9.5.0.25 # ld -v
o util-linux 2.10o # fdformat --version
-o modutils 2.4.2 # insmod -V
+o module-init-tools 0.9 # rmmod -V
o e2fsprogs 1.29 # tune2fs
o jfsutils 1.0.14 # fsck.jfs -V
o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs
@@ -141,14 +141,11 @@ If the unthinkable happens and your kernel oopses, you'll need a 2.4
version of ksymoops to decode the report; see REPORTING-BUGS in the
root of the Linux source for more information.
-Modutils
+Module-Init-Tools
--------
-Upgrade to recent modutils to fix various outstanding bugs which are
-seen more frequently under 2.4.x, and to enable auto-loading of USB
-modules. In addition, the layout of modules under
-/lib/modules/`uname -r`/ has been made more sane. This change also
-requires that you upgrade to a recent modutils.
+A new module loader is now in the kernel that requires module-init-tools
+to use. It is backward compatible with the 2.4.x series kernels.
Mkinitrd
--------
@@ -306,7 +303,7 @@ o <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4/>
Modutils
--------
-o <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.4/>
+o <ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/>
Mkinitrd
--------
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 12b0086b75ea..b3c00ed92451 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -213,7 +213,7 @@ The top Makefile exports the following variables:
$(GENKSYMS) contains the command used to generate kernel symbol
signatures when CONFIG_MODVERSIONS is enabled. The genksyms
- command comes from the modutils package.
+ command comes from the module-init-tools package.
CROSS_COMPILE
diff --git a/Documentation/modules.txt b/Documentation/modules.txt
index 833a05804052..e30516d41121 100644
--- a/Documentation/modules.txt
+++ b/Documentation/modules.txt
@@ -3,12 +3,11 @@ in the Linux kernel. This is not a technical description on
the internals of module, but mostly a sample of how to compile
and use modules.
-Note: You should ensure that the modutils-X.Y.Z.tar.gz you are using
-is the most up to date one for this kernel. The "X.Y.Z" will reflect
-the kernel version at the time of the release of the modules package.
-Some older modules packages aren't aware of some of the newer modular
-features that the kernel now supports. The current required version
-is listed in the file linux/Documentation/Changes.
+Note: You should ensure that the module-init-tools-X.Y.Z.tar.gz you
+are using is the most up to date one for this kernel. Some older
+modules packages aren't aware of some of the newer modular features
+that the kernel now supports. The current required version is listed
+in the file linux/Documentation/Changes.
* * * NOTE * * *
The kernel has been changed to remove kerneld support and use
@@ -124,7 +123,8 @@ And, yes, there _are_ man-pages for all this...
To use modprobe successfully, you generally place the following
command in your /etc/rc.d/rc.S script. (Read more about this in the
-"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".)
+"rc.hints" file in the module utilities package,
+"module-init-tools-x.y.z.tar.gz".)
/sbin/depmod -a
diff --git a/Documentation/networking/z8530drv.txt b/Documentation/networking/z8530drv.txt
index 60f453d18f89..2206abbc3e1b 100644
--- a/Documentation/networking/z8530drv.txt
+++ b/Documentation/networking/z8530drv.txt
@@ -54,7 +54,7 @@ Before you can use a module, you'll have to load it with
insmod scc.o
-please read 'man insmod' that comes with modutils.
+please read 'man insmod' that comes with module-init-tools.
You should include the insmod in one of the /etc/rc.d/rc.* files,
and don't forget to insert a call of sccinit after that. It
diff --git a/Documentation/sound/oss/Introduction b/Documentation/sound/oss/Introduction
index 0b7fdc9593a4..90b41f8c3b4c 100644
--- a/Documentation/sound/oss/Introduction
+++ b/Documentation/sound/oss/Introduction
@@ -119,9 +119,9 @@ the README takes precedence.
6. Make the modules and install them (make modules; make modules_install).
-Note, for 2.4.x kernels, make sure you have the newer modutils
-loaded or modules will not be loaded properly. 2.4.x changed the
-layout of /lib/modules/2.4.x and requires an updated modutils.
+Note, for 2.5.x kernels, make sure you have the newer module-init-tools
+installed or modules will not be loaded properly. 2.5.x requires an
+updated module-init-tools.
Plug and Play (PnP:
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index ac873ad4ce6e..424ccd9f7c45 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -286,9 +286,9 @@ can be ORed together:
1 - A module with a non-GPL license has been loaded, this
includes modules with no license.
- Set by modutils >= 2.4.9.
+ Set by modutils >= 2.4.9 and module-init-tools.
2 - A module was force loaded by insmod -f.
- Set by modutils >= 2.4.9.
+ Set by modutils >= 2.4.9 and module-init-tools.
4 - Unsafe SMP processors: SMP with CPUs not designed for SMP.
==============================================================
diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt
new file mode 100644
index 000000000000..2950ab0012bf
--- /dev/null
+++ b/Documentation/uml/UserModeLinux-HOWTO.txt
@@ -0,0 +1,4686 @@
+ User Mode Linux HOWTO
+ User Mode Linux Core Team
+ Mon Nov 18 14:16:16 EST 2002
+
+ This document describes the use and abuse of Jeff Dike's User Mode
+ Linux: a port of the Linux kernel as a normal Intel Linux process.
+ ______________________________________________________________________
+
+ Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1. Introduction
+
+ 1.1 How is User Mode Linux Different?
+ 1.2 Why Would I Want User Mode Linux?
+
+ 2. Compiling the kernel and modules
+
+ 2.1 Compiling the kernel
+ 2.2 Compiling and installing kernel modules
+ 2.3 Compiling and installing uml_utilities
+
+ 3. Running UML and logging in
+
+ 3.1 Running UML
+ 3.2 Logging in
+ 3.3 Examples
+
+ 4. UML on 2G/2G hosts
+
+ 4.1 Introduction
+ 4.2 The problem
+ 4.3 The solution
+
+ 5. Setting up serial lines and consoles
+
+ 5.1 Specifying the device
+ 5.2 Specifying the channel
+ 5.3 Examples
+
+ 6. Setting up the network
+
+ 6.1 General setup
+ 6.2 Userspace daemons
+ 6.3 Specifying ethernet addresses
+ 6.4 UML interface setup
+ 6.5 Multicast
+ 6.6 TUN/TAP with the uml_net helper
+ 6.7 TUN/TAP with a preconfigured tap device
+ 6.8 Ethertap
+ 6.9 The switch daemon
+ 6.10 Slip
+ 6.11 Slirp
+ 6.12 pcap
+ 6.13 Setting up the host yourself
+
+ 7. Sharing Filesystems between Virtual Machines
+
+ 7.1 A warning
+ 7.2 Using layered block devices
+ 7.3 Note!
+ 7.4 Another warning
+ 7.5 uml_moo : Merging a COW file with its backing file
+
+ 8. Creating filesystems
+
+ 8.1 Create the filesystem file
+ 8.2 Assign the file to a UML device
+ 8.3 Creating and mounting the filesystem
+
+ 9. Host file access
+
+ 9.1 Using hostfs
+ 9.2 hostfs as the root filesystem
+ 9.3 Building hostfs
+
+ 10. The Management Console
+ 10.1 version
+ 10.2 halt and reboot
+ 10.3 config
+ 10.4 remove
+ 10.5 sysrq
+ 10.6 help
+ 10.7 cad
+ 10.8 stop
+ 10.9 go
+
+ 11. Kernel debugging
+
+ 11.1 Starting the kernel under gdb
+ 11.2 Examining sleeping processes
+ 11.3 Running ddd on UML
+ 11.4 Debugging modules
+ 11.5 Attaching gdb to the kernel
+ 11.6 Using alternate debuggers
+
+ 12. Kernel debugging examples
+
+ 12.1 The case of the hung fsck
+ 12.2 Episode 2: The case of the hung fsck
+
+ 13. What to do when UML doesn't work
+
+ 13.1 Strange compilation errors when you build from source
+ 13.2 UML hangs on boot after mounting devfs
+ 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem
+ 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid'
+ 13.5 UML doesn't work when /tmp is an NFS filesystem
+ 13.6 UML hangs on boot when compiled with gprof support
+ 13.7 syslogd dies with a SIGTERM on startup
+ 13.8 TUN/TAP networking doesn't work on a 2.4 host
+ 13.9 You can network to the host but not to other machines on the net
+ 13.10 I have no root and I want to scream
+ 13.11 UML build conflict between ptrace.h and ucontext.h
+ 13.12 The UML BogoMips is exactly half the host's BogoMips
+ 13.13 When you run UML, it immediately segfaults
+ 13.14 xterms appear, then immediately disappear
+ 13.15 Any other panic, hang, or strange behavior
+
+ 14. Diagnosing Problems
+
+ 14.1 Case 1 : Normal kernel panics
+ 14.2 Case 2 : Tracing thread panics
+ 14.3 Case 3 : Tracing thread panics caused by other threads
+ 14.4 Case 4 : Hangs
+
+ 15. Thanks
+
+ 15.1 Code and Documentation
+ 15.2 Flushing out bugs
+ 15.3 Buglets and clean-ups
+ 15.4 Case Studies
+ 15.5 Other contributions
+
+
+ ______________________________________________________________________
+
+ 11.. IInnttrroodduuccttiioonn
+
+ Welcome to User Mode Linux. It's going to be fun.
+
+
+
+ 11..11.. HHooww iiss UUsseerr MMooddee LLiinnuuxx DDiiffffeerreenntt??
+
+ Normally, the Linux Kernel talks straight to your hardware (video
+ card, keyboard, hard drives, etc), and any programs which run ask the
+ kernel to operate the hardware, like so:
+
+
+
+ +-----------+-----------+----+
+ | Process 1 | Process 2 | ...|
+ +-----------+-----------+----+
+ | Linux Kernel |
+ +----------------------------+
+ | Hardware |
+ +----------------------------+
+
+
+
+
+ The User Mode Linux Kernel is different; instead of talking to the
+ hardware, it talks to a `real' Linux kernel (called the `host kernel'
+ from now on), like any other program. Programs can then run inside
+ User-Mode Linux as if they were running under a normal kernel, like
+ so:
+
+
+
+ +----------------+
+ | Process 2 | ...|
+ +-----------+----------------+
+ | Process 1 | User-Mode Linux|
+ +----------------------------+
+ | Linux Kernel |
+ +----------------------------+
+ | Hardware |
+ +----------------------------+
+
+
+
+
+
+ 11..22.. WWhhyy WWoouulldd II WWaanntt UUsseerr MMooddee LLiinnuuxx??
+
+
+ 1. If User Mode Linux crashes, your host kernel is still fine.
+
+ 2. You can run a usermode kernel as a non-root user.
+
+ 3. You can debug the User Mode Linux like any normal process.
+
+ 4. You can run gprof (profiling) and gcov (coverage testing).
+
+ 5. You can play with your kernel without breaking things.
+
+ 6. You can use it as a sandbox for testing new apps.
+
+ 7. You can try new development kernels safely.
+
+ 8. You can run different distributions simultaneously.
+
+ 9. It's extremely fun.
+
+
+
+
+
+ 22.. CCoommppiilliinngg tthhee kkeerrnneell aanndd mmoodduulleess
+
+
+
+
+ 22..11.. CCoommppiilliinngg tthhee kkeerrnneell
+
+
+ Compiling the user mode kernel is just like compiling any other
+ kernel. Let's go through the steps, using 2.4.0-prerelease (current
+ as of this writing) as an example:
+
+
+ 1. Download the latest UML patch from
+
+ the download page <http://user-mode-linux.sourceforge.net/dl-
+ sf.html>
+
+ In this example, the file is uml-patch-2.4.0-prerelease.bz2.
+
+
+ 2. Download the matching kernel from your favourite kernel mirror,
+ such as:
+
+ ftp://ftp.ca.kernel.org/pub/kernel/v2.4/linux-2.4.0-prerelease.tar.bz2
+ <ftp://ftp.ca.kernel.org/pub/kernel/v2.4/linux-2.4.0-prerelease.tar.bz2>
+ .
+
+
+ 3. Make a directory and unpack the kernel into it.
+
+
+
+ host%
+ mkdir ~/uml
+
+
+
+
+
+
+ host%
+ cd ~/uml
+
+
+
+
+
+
+ host%
+ tar -xzvf linux-2.4.0-prerelease.tar.bz2
+
+
+
+
+
+
+ 4. Apply the patch using
+
+
+
+ host%
+ cd ~/uml/linux
+
+
+
+ host%
+ bzcat uml-patch-2.4.0-prerelease.bz2 | patch -p1
+
+
+
+
+
+
+ 5. Run your favorite config; `make xconfig ARCH=um' is the most
+ convenient. `make config ARCH=um' and 'make menuconfig ARCH=um'
+ will work as well. The defaults will give you a useful kernel. If
+ you want to change something, go ahead, it probably won't hurt
+ anything.
+
+
+ Note: If the host is configured with a 2G/2G address space split
+ rather than the usual 3G/1G split, then the packaged UML binaries
+ will not run. They will immediately segfault. See ``UML on 2G/2G
+ hosts'' for the scoop on running UML on your system.
+
+
+
+ 6. Finish with `make linux ARCH=um': the result is a file called
+ `linux' in the top directory of your source tree.
+
+ Make sure that you don't build this kernel in /usr/src/linux. On some
+ distributions, /usr/include/asm is a link into this pool. The user-
+ mode build changes the other end of that link, and things that include
+ <asm/anything.h> stop compiling.
+
+ The sources are also available from cvs at the project's cvs page,
+ which has directions on getting the sources. You can also browse the
+ CVS pool from there.
+
+ If you get the CVS sources, you will have to check them out into an
+ empty directory. You will then have to copy each file into the
+ corresponding directory in the appropriate kernel pool.
+
+ If you don't have the latest kernel pool, you can get the
+ corresponding user-mode sources with
+
+
+ host% cvs co -r v_2_3_x linux
+
+
+
+
+ where 'x' is the version in your pool. Note that you will not get the
+ bug fixes and enhancements that have gone into subsequent releases.
+
+
+ If you build your own kernel, and want to boot it from one of the
+ filesystems distributed from this site, then, in nearly all cases,
+ devfs must be compiled into the kernel and mounted at boot time. The
+ exception is the SuSE filesystem. For this, devfs must either not be
+ in the kernel at all, or "devfs=nomount" must be on the kernel command
+ line. Any disagreement between the kernel and the filesystem being
+ booted about whether devfs is being used will result in the boot
+ getting no further than single-user mode.
+
+
+ If you don't want to use devfs, you can remove the need for it from a
+ filesystem by copying /dev from someplace, making a bunch of /dev/ubd
+ devices:
+
+
+ UML# for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $i; done
+
+
+
+
+ and changing /etc/fstab and /etc/inittab to refer to the non-devfs
+ devices.
+
+
+
+ 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess
+
+ UML modules are built in the same way as the native kernel (with the
+ exception of the 'ARCH=um' that you always need for UML):
+
+
+ host% make modules ARCH=um
+
+
+
+
+ Any modules that you want to load into this kernel need to be built in
+ the user-mode pool. Modules from the native kernel won't work.
+
+ You can install them by using ftp or something to copy them into the
+ virtual machine and dropping them into /lib/modules/`uname -r`.
+
+ You can also get the kernel build process to install them as follows:
+
+ 1. with the kernel not booted, mount the root filesystem in the top
+ level of the kernel pool:
+
+
+ host% mount root_fs mnt -o loop
+
+
+
+
+
+
+ 2. run
+
+
+ host%
+ make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um
+
+
+
+
+
+
+ 3. unmount the filesystem
+
+
+ host% umount mnt
+
+
+
+
+
+
+ 4. boot the kernel on it
+
+
+ When the system is booted, you can use insmod as usual to get the
+ modules into the kernel. A number of things have been loaded into UML
+ as modules, especially filesystems and network protocols and filters,
+ so most symbols which need to be exported probably already are.
+ However, if you do find symbols that need exporting, let us
+ <http://user-mode-linux.sourceforge.net/contacts.html> know, and
+ they'll be "taken care of".
+
+
+
+ 22..33.. CCoommppiilliinngg aanndd iinnssttaalllliinngg uummll__uuttiilliittiieess
+
+ Many features of the UML kernel require a user-space helper program,
+ so a uml_utilities package is distributed separately from the kernel
+ patch which provides these helpers. Included within this is:
+
+ +o port-helper - Used by consoles which connect to xterms or ports
+
+ +o tunctl - Configuration tool to create and delete tap devices
+
+ +o uml_net - Setuid binary for automatic tap device configuration
+
+ +o uml_switch - User-space virtual switch required for daemon
+ transport
+
+ The uml_utilities tree is compiled with:
+
+
+ host#
+ make && make install
+
+
+
+
+ Note that UML kernel patches may require a specific version of the
+ uml_utilities distribution. If you don't keep up with the mailing
+ lists, ensure that you have the latest release of uml_utilities if you
+ are experiencing problems with your UML kernel, particularly when
+ dealing with consoles or command-line switches to the helper programs
+
+
+
+
+
+
+
+
+ 33.. RRuunnnniinngg UUMMLL aanndd llooggggiinngg iinn
+
+
+
+ 33..11.. RRuunnnniinngg UUMMLL
+
+ It runs on 2.2.15 or later, and all 2.4 kernels.
+
+
+ Booting UML is straightforward. Simply run 'linux': it will try to
+ mount the file `root_fs' in the current directory. You do not need to
+ run it as root. If your root filesystem is not named `root_fs', then
+ you need to put a `ubd0=root_fs_whatever' switch on the linux command
+ line.
+
+
+ You will need a filesystem to boot UML from. There are a number
+ available for download from here <http://user-mode-
+ linux.sourceforge.net/dl-sf.html> . There are also several tools
+ <http://user-mode-linux.sourceforge.net/fs_making.html> which can be
+ used to generate UML-compatible filesystem images from media.
+ The kernel will boot up and present you with a login prompt.
+
+
+ Note: If the host is configured with a 2G/2G address space split
+ rather than the usual 3G/1G split, then the packaged UML binaries will
+ not run. They will immediately segfault. See ``UML on 2G/2G hosts''
+ for the scoop on running UML on your system.
+
+
+
+ 33..22.. LLooggggiinngg iinn
+
+
+
+ The prepackaged filesystems have a root account with password 'root'
+ and a user account with password 'user'. The login banner will
+ generally tell you how to log in. So, you log in and you will find
+ yourself inside a little virtual machine. Our filesystems have a
+ variety of commands and utilities installed (and it is fairly easy to
+ add more), so you will have a lot of tools with which to poke around
+ the system.
+
+ There are a couple of other ways to log in:
+
+ +o On a virtual console
+
+
+
+ Each virtual console that is configured (i.e. the device exists in
+ /dev and /etc/inittab runs a getty on it) will come up in its own
+ xterm. If you get tired of the xterms, read ``Setting up serial
+ lines and consoles'' to see how to attach the consoles to
+ something else, like host ptys.
+
+
+
+ +o Over the serial line
+
+
+ In the boot output, find a line that looks like:
+
+
+
+ serial line 0 assigned pty /dev/ptyp1
+
+
+
+
+ Attach your favorite terminal program to the corresponding tty. I.e.
+ for minicom, the command would be
+
+
+ host% minicom -o -p /dev/ttyp1
+
+
+
+
+
+
+ +o Over the net
+
+
+ If the network is running, then you can telnet to the virtual
+ machine and log in to it. See ``Setting up the network'' to learn
+ about setting up a virtual network.
+
+ When you're done using it, run halt, and the kernel will bring itself
+ down and the process will exit.
+
+
+ 33..33.. EExxaammpplleess
+
+ Here are some examples of UML in action:
+
+ +o A login session <http://user-mode-linux.sourceforge.net/login.html>
+
+ +o A virtual network <http://user-mode-linux.sourceforge.net/net.html>
+
+
+
+
+
+
+
+ 44.. UUMMLL oonn 22GG//22GG hhoossttss
+
+
+
+
+ 44..11.. IInnttrroodduuccttiioonn
+
+
+ Most Linux machines are configured so that the kernel occupies the
+ upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and
+ processes use the lower 3G (0x00000000 - 0xbfffffff). However, some
+ machine are configured with a 2G/2G split, with the kernel occupying
+ the upper 2G (0x80000000 - 0xffffffff) and processes using the lower
+ 2G (0x00000000 - 0x7fffffff).
+
+
+
+
+ 44..22.. TThhee pprroobblleemm
+
+
+ The prebuilt UML binaries on this site will not run on 2G/2G hosts
+ because UML occupies the upper .5G of the 3G process address space
+ (0xa0000000 - 0xbfffffff). Obviously, on 2G/2G hosts, this is right
+ in the middle of the kernel address space, so UML won't even load - it
+ will immediately segfault.
+
+
+
+
+ 44..33.. TThhee ssoolluuttiioonn
+
+
+ The fix for this is to rebuild UML from source after enabling
+ CONFIG_HOST_2G_2G (under 'General Setup'). This will cause UML to
+ load itself in the top .5G of that smaller process address space,
+ where it will run fine. See ``Compiling the kernel and modules'' if
+ you need help building UML from source.
+
+
+
+
+
+
+
+
+
+
+ 55.. SSeettttiinngg uupp sseerriiaall lliinneess aanndd ccoonnssoolleess
+
+
+ It is possible to attach UML serial lines and consoles to many types
+ of host I/O channels by specifying them on the command line.
+
+
+ You can attach them to host ptys, ttys, file descriptors, and ports.
+ This allows you to do things like
+
+ +o have a UML console appear on an unused host console,
+
+ +o hook two virtual machines together by having one attach to a pty
+ and having the other attach to the corresponding tty
+
+ +o make a virtual machine accessible from the net by attaching a
+ console to a port on the host.
+
+
+ The general format of the command line option is device=channel.
+
+
+
+ 55..11.. SSppeecciiffyyiinngg tthhee ddeevviiccee
+
+ Devices are specified with "con" or "ssl" (console or serial line,
+ respectively), optionally with a device number if you are talking
+ about a specific device.
+
+
+ Using just "con" or "ssl" describes all of the consoles or serial
+ lines. If you want to talk about console #3 or serial line #10, they
+ would be "con3" and "ssl10", respectively.
+
+
+ A specific device name will override a less general "con=" or "ssl=".
+ So, for example, you can assign a pty to each of the serial lines
+ except for the first two like this:
+
+
+ ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1
+
+
+
+
+ The specificity of the device name is all that matters; order on the
+ command line is irrelevant.
+
+
+
+ 55..22.. SSppeecciiffyyiinngg tthhee cchhaannnneell
+
+ There are a number of different types of channels to attach a UML
+ device to, each with a different way of specifying exactly what to
+ attach to.
+
+ +o pseudo-terminals - device=pty pts terminals - device=pts
+
+
+ This will cause UML to allocate a free host pseudo-terminal for the
+ device. The terminal that it got will be announced in the boot
+ log. You access it by attaching a terminal program to the
+ corresponding tty:
+
+ +o screen /dev/pts/n
+
+ +o screen /dev/ttyxx
+
+ +o minicom -o -p /dev/ttyxx - minicom seems not able to handle pts
+ devices
+
+ +o kermit - start it up, 'open' the device, then 'connect'
+
+
+
+
+
+ +o terminals - device=tty:tty device file
+
+
+ This will make UML attach the device to the specified tty (i.e
+
+
+ con1=tty:/dev/tty3
+
+
+
+
+ will attach UML's console 1 to the host's /dev/tty3). If the tty that
+ you specify is the slave end of a tty/pty pair, something else must
+ have already opened the corresponding pty in order for this to work.
+
+
+
+
+
+ +o xterms - device=xterm
+
+
+ UML will run an xterm and the device will be attached to it.
+
+
+
+
+
+ +o Port - device=port:port number
+
+
+ This will attach the UML devices to the specified host port.
+ Attaching console 1 to the host's port 9000 would be done like
+ this:
+
+
+ con1=port:9000
+
+
+
+
+ Attaching all the serial lines to that port would be done similarly:
+
+
+ ssl=port:9000
+
+
+
+
+ You access these devices by telnetting to that port. Each active tel-
+ net session gets a different device. If there are more telnets to a
+ port than UML devices attached to it, then the extra telnet sessions
+ will block until an existing telnet detaches, or until another device
+ becomes active (i.e. by being activated in /etc/inittab).
+
+ This channel has the advantage that you can both attach multiple UML
+ devices to it and know how to access them without reading the UML boot
+ log. It is also unique in allowing access to a UML from remote
+ machines without requiring that the UML be networked. This could be
+ useful in allowing public access to UMLs because they would be
+ accessible from the net, but wouldn't need any kind of network
+ filtering or access control because they would have no network access.
+
+
+ If you attach the main console to a portal, then the UML boot will
+ appear to hang. In reality, it's waiting for a telnet to connect, at
+ which point the boot will proceed.
+
+
+
+
+
+ +o already-existing file descriptors - device=file descriptor
+
+
+ If you set up a file descriptor on the UML command line, you can
+ attach a UML device to it. This is most commonly used to put the
+ main console back on stdin and stdout after assigning all the other
+ consoles to something else:
+
+
+ con0=fd:0,fd:1 con=pts
+
+
+
+
+
+
+
+
+ +o Nothing - device=null
+
+
+ This allows the device to be opened, in contrast to 'none', but
+ reads will block, and writes will succeed and the data will be
+ thrown out.
+
+
+
+
+
+ +o None - device=none
+
+
+ This causes the device to disappear. If you are using devfs, the
+ device will not appear in /dev. If not, then attempts to open it
+ will return -ENODEV.
+
+
+
+ You can also specify different input and output channels for a device
+ by putting a comma between them:
+
+
+ ssl3=tty:/dev/tty2,xterm
+
+
+
+
+ will cause serial line 3 to accept input on the host's /dev/tty3 and
+ display output on an xterm. That's a silly example - the most common
+ use of this syntax is to reattach the main console to stdin and stdout
+ as shown above.
+
+
+ If you decide to move the main console away from stdin/stdout, the
+ initial boot output will appear in the terminal that you're running
+ UML in. However, once the console driver has been officially
+ initialized, then the boot output will start appearing wherever you
+ specified that console 0 should be. That device will receive all
+ subsequent output.
+
+
+
+ 55..33.. EExxaammpplleess
+
+ There are a number of interesting things you can do with this
+ capability.
+
+
+ First, this is how you get rid of those bleeding console xterms by
+ attaching them to host ptys:
+
+
+ con=pty con0=fd:0,fd:1
+
+
+
+
+ This will make a UML console take over an unused host virtual console,
+ so that when you switch to it, you will see the UML login prompt
+ rather than the host login prompt:
+
+
+ con1=tty:/dev/tty6
+
+
+
+
+ You can attach two virtual machines together with what amounts to a
+ serial line as follows:
+
+ Run one UML with a serial line attached to a pty -
+
+
+ ssl1=pty
+
+
+
+
+ Look at the boot log to see what pty it got (this example will assume
+ that it got /dev/ptyp1).
+
+ Boot the other UML with a serial line attached to the corresponding
+ tty -
+
+
+ ssl1=tty:/dev/ttyp1
+
+
+
+
+ Log in, make sure that it has no getty on that serial line, attach a
+ terminal program like minicom to it, and you should see the login
+ prompt of the other virtual machine.
+
+
+ 66.. SSeettttiinngg uupp tthhee nneettwwoorrkk
+
+
+
+ This page describes how to set up the various transports and to
+ provide a UML instance with network access to the host, other machines
+ on the local net, and the rest of the net.
+
+
+ As of 2.4.5, UML networking has been completely redone to make it much
+ easier to set up, fix bugs, and add new features.
+
+
+ There is a new helper, uml_net, which does the host setup that
+ requires root privileges.
+
+
+ There are currently five transport types available for a UML virtual
+ machine to exchange packets with other hosts:
+
+ +o ethertap
+
+ +o TUN/TAP
+
+ +o Multicast
+
+ +o a switch daemon
+
+ +o slip
+
+ +o slirp
+
+ +o pcap
+
+ The TUN/TAP, ethertap, slip, and slirp transports allow a UML
+ instance to exchange packets with the host. They may be directed
+ to the host or the host may just act as a router to provide access
+ to other physical or virtual machines.
+
+
+ The pcap transport is a synthetic read-only interface, using the
+ libpcap binary to collect packets from interfaces on the host and
+ filter them. This is useful for building preconfigured traffic
+ monitors or sniffers.
+
+
+ The daemon and multicast transports provide a completely virtual
+ network to other virtual machines. This network is completely
+ disconnected from the physical network unless one of the virtual
+ machines on it is acting as a gateway.
+
+
+ With so many host transports, which one should you use? Here's when
+ you should use each one:
+
+ +o ethertap - if you want access to the host networking and it is
+ running 2.2
+
+ +o TUN/TAP - if you want access to the host networking and it is
+ running 2.4. Also, the TUN/TAP transport is able to use a
+ preconfigured device, allowing it to avoid using the setuid uml_net
+ helper, which is a security advantage.
+
+ +o Multicast - if you want a purely virtual network and you don't want
+ to set up anything but the UML
+
+ +o a switch daemon - if you want a purely virtual network and you
+ don't mind running the daemon in order to get somewhat better
+ performance
+
+ +o slip - there is no particular reason to run the slip backend unless
+ ethertap and TUN/TAP are just not available for some reason
+
+ +o slirp - if you don't have root access on the host to setup
+ networking, or if you don't want to allocate an IP to your UML
+
+ +o pcap - not much use for actual network connectivity, but great for
+ monitoring traffic on the host
+
+ Ethertap is available on 2.4 and works fine. TUN/TAP is preferred
+ to it because it has better performance and ethertap is officially
+ considered obsolete in 2.4. Also, the root helper only needs to
+ run occasionally for TUN/TAP, rather than handling every packet, as
+ it does with ethertap. This is a slight security advantage since
+ it provides fewer opportunities for a nasty UML user to somehow
+ exploit the helper's root privileges.
+
+
+ 66..11.. GGeenneerraall sseettuupp
+
+ First, you must have the virtual network enabled in your UML. If are
+ running a prebuilt kernel from this site, everything is already
+ enabled. If you build the kernel yourself, under the "Network device
+ support" menu, enable "Network device support", and then the three
+ transports.
+
+
+ The next step is to provide a network device to the virtual machine.
+ This is done by describing it on the kernel command line.
+
+ The general format is
+
+
+ eth <n> = <transport> , <transport args>
+
+
+
+
+ For example, a virtual ethernet device may be attached to a host
+ ethertap device as follows:
+
+
+ eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254
+
+
+
+
+ This sets up eth0 inside the virtual machine to attach itself to the
+ host /dev/tap0, assigns it an ethernet address, and assigns the host
+ tap0 interface an IP address.
+
+
+
+ Note that the IP address you assign to the host end of the tap device
+ must be different than the IP you assign to the eth device inside UML.
+ If you are short on IPs and don't want to comsume two per UML, then
+ you can reuse the host's eth IP address for the host ends of the tap
+ devices. Internally, the UMLs must still get unique IPs for their eth
+ devices. You can also give the UMLs non-routable IPs (192.168.x.x or
+ 10.x.x.x) and have the host masquerade them. This will let outgoing
+ connections work, but incoming connections won't without more work,
+ such as port forwarding from the host.
+ Also note that when you configure the host side of an interface, it is
+ only acting as a gateway. It will respond to pings sent to it
+ locally, but is not useful to do that since it's a host interface.
+ You are not talking to the UML when you ping that interface and get a
+ response.
+
+
+ You can also add devices to a UML and remove them at runtime. See the
+ ``The Management Console'' page for details.
+
+
+ The sections below describe this in more detail.
+
+
+ Once you've decided how you're going to set up the devices, you boot
+ UML, log in, configure the UML side of the devices, and set up routes
+ to the outside world. At that point, you will be able to talk to any
+ other machines, physical or virtual, on the net.
+
+
+ If ifconfig inside UML fails and the network refuses to come up, run
+ tell you what went wrong.
+
+
+
+ 66..22.. UUsseerrssppaaccee ddaaeemmoonnss
+
+ You will likely need the setuid helper, or the switch daemon, or both.
+ They are both installed with the RPM and deb, so if you've installed
+ either, you can skip the rest of this section.
+
+
+ If not, then you need to check them out of CVS, build them, and
+ install them. The helper is uml_net, in CVS /tools/uml_net, and the
+ daemon is uml_switch, in CVS /tools/uml_router. They are both built
+ with a plain 'make'. Both need to be installed in a directory that's
+ in your path - /usr/bin is recommend. On top of that, uml_net needs
+ to be setuid root.
+
+
+
+ 66..33.. SSppeecciiffyyiinngg eetthheerrnneett aaddddrreesssseess
+
+ Below, you will see that the TUN/TAP, ethertap, and daemon interfaces
+ allow you to specify hardware addresses for the virtual ethernet
+ devices. This is generally not necessary. If you don't have a
+ specific reason to do it, you probably shouldn't. If one is not
+ specified on the command line, the driver will assign one based on the
+ device IP address. It will provide the address fe:fd:nn:nn:nn:nn
+ where nn.nn.nn.nn is the device IP address. This is nearly always
+ sufficient to guarantee a unique hardware address for the device. A
+ couple of exceptions are:
+
+ +o Another set of virtual ethernet devices are on the same network and
+ they are assigned hardware addresses using a different scheme which
+ may conflict with the UML IP address-based scheme
+
+ +o You aren't going to use the device for IP networking, so you don't
+ assign the device an IP address
+
+ If you let the driver provide the hardware address, you should make
+ sure that the device IP address is known before the interface is
+ brought up. So, inside UML, this will guarantee that:
+
+
+
+ UML#
+ ifconfig eth0 192.168.0.250 up
+
+
+
+
+ If you decide to assign the hardware address yourself, make sure that
+ the first byte of the address is even. Addresses with an odd first
+ byte are broadcast addresses, which you don't want assigned to a
+ device.
+
+
+
+ 66..44.. UUMMLL iinntteerrffaaccee sseettuupp
+
+ Once the network devices have been described on the command line, you
+ should boot UML and log in.
+
+
+ The first thing to do is bring the interface up:
+
+
+ UML# ifconfig ethn ip-address up
+
+
+
+
+ You should be able to ping the host at this point.
+
+
+ To reach the rest of the world, you should set a default route to the
+ host:
+
+
+ UML# route add default gw host ip
+
+
+
+
+ Again, with host ip of 192.168.0.4:
+
+
+ UML# route add default gw 192.168.0.4
+
+
+
+
+ This page used to recommend setting a network route to your local net.
+ This is wrong, because it will cause UML to try to figure out hardware
+ addresses of the local machines by arping on the interface to the
+ host. Since that interface is basically a single strand of ethernet
+ with two nodes on it (UML and the host) and arp requests don't cross
+ networks, they will fail to elicit any responses. So, what you want
+ is for UML to just blindly throw all packets at the host and let it
+ figure out what to do with them, which is what leaving out the network
+ route and adding the default route does.
+
+
+ Note: If you can't communicate with other hosts on your physical
+ ethernet, it's probably because of a network route that's
+ automatically set up. If you run 'route -n' and see a route that
+ looks like this:
+
+
+
+
+ Destination Gateway Genmask Flags Metric Ref Use Iface
+ 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
+
+
+
+
+ with a mask that's not 255.255.255.255, then replace it with a route
+ to your host:
+
+
+ UML#
+ route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0
+
+
+
+
+
+
+ UML#
+ route add -host 192.168.0.4 dev eth0
+
+
+
+
+ This, plus the default route to the host, will allow UML to exchange
+ packets with any machine on your ethernet.
+
+
+
+ 66..55.. MMuullttiiccaasstt
+
+ The simplest way to set up a virtual network between multiple UMLs is
+ to use the mcast transport. This was written by Harald Welte and is
+ present in UML version 2.4.5-5um and later. Your system must have
+ multicast enabled in the kernel and there must be a multicast-capable
+ network device on the host. Normally, this is eth0, but if there is
+ no ethernet card on the host, then you will likely get strange error
+ messages when you bring the device up inside UML.
+
+
+ To use it, run two UMLs with
+
+
+ eth0=mcast
+
+
+
+
+ on their command lines. Log in, configure the ethernet device in each
+ machine with different IP addresses:
+
+
+ UML1# ifconfig eth0 192.168.0.254
+
+
+
+
+
+
+ UML2# ifconfig eth0 192.168.0.253
+
+
+
+
+ and they should be able to talk to each other.
+
+ The full set of command line options for this transport are
+
+
+
+ ethn=mcast,ethernet address,multicast
+ address,multicast port,ttl
+
+
+
+
+ Harald's original README is here <http://user-mode-linux.source-
+ forge.net/text/mcast.txt> and explains these in detail, as well as
+ some other issues.
+
+
+
+ 66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr
+
+ TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the
+ host. The TUN/TAP backend has been in UML since 2.4.9-3um.
+
+
+ The easiest way to get up and running is to let the setuid uml_net
+ helper do the host setup for you. This involves insmod-ing the tun.o
+ module if necessary, configuring the device, and setting up IP
+ forwarding, routing, and proxy arp. If you are new to UML networking,
+ do this first. If you're concerned about the security implications of
+ the setuid helper, use it to get up and running, then read the next
+ section to see how to have UML use a preconfigured tap device, which
+ avoids the use of uml_net.
+
+
+ If you specify an IP address for the host side of the device, the
+ uml_net helper will do all necessary setup on the host - the only
+ requirement is that TUN/TAP be available, either built in to the host
+ kernel or as the tun.o module.
+
+ The format of the command line switch to attach a device to a TUN/TAP
+ device is
+
+
+ eth <n> =tuntap,,, <IP address>
+
+
+
+
+ For example, this argument will attach the UML's eth0 to the next
+ available tap device and assign an ethernet address to it based on its
+ IP address
+
+
+ eth0=tuntap,,,192.168.0.254
+
+
+
+
+
+
+ Note that the IP address that must be used for the eth device inside
+ UML is fixed by the routing and proxy arp that is set up on the
+ TUN/TAP device on the host. You can use a different one, but it won't
+ work because reply packets won't reach the UML. This is a feature.
+ It prevents a nasty UML user from doing things like setting the UML IP
+ to the same as the network's nameserver or mail server.
+
+
+ There are a couple potential problems with running the TUN/TAP
+ transport on a 2.4 host kernel
+
+ +o TUN/TAP seems not to work on 2.4.3 and earlier. Upgrade the host
+ kernel or use the ethertap transport.
+
+ +o With an upgraded kernel, TUN/TAP may fail with
+
+
+ File descriptor in bad state
+
+
+
+
+ This is due to a header mismatch between the upgraded kernel and the
+ kernel that was originally installed on the machine. The fix is to
+ make sure that /usr/src/linux points to the headers for the running
+ kernel.
+
+ These were pointed out by Tim Robinson <timro at trkr dot net> in
+ <http://www.geocrawler.com/lists/3/SourceForge/597/0/> name="this uml-
+ user post"> .
+
+
+
+ 66..77.. TTUUNN//TTAAPP wwiitthh aa pprreeccoonnffiigguurreedd ttaapp ddeevviiccee
+
+ If you prefer not to have UML use uml_net (which is somewhat
+ insecure), with UML 2.4.17-11, you can set up a TUN/TAP device
+ beforehand. The setup needs to be done as root, but once that's done,
+ there is no need for root assistance. Setting up the device is done
+ as follows:
+
+ +o Create the device with tunctl (available from the UML utilities
+ tarball)
+
+
+
+
+ host# tunctl -u uid
+
+
+
+
+ where uid is the user id or username that UML will be run as. This
+ will tell you what device was created.
+
+ +o Configure the device IP (change IP addresses and device name to
+ suit)
+
+
+
+
+ host# ifconfig tap0 192.168.0.254 up
+
+
+
+
+
+ +o Set up routing and arping if desired - this is my recipe, there are
+ other ways of doing the same thing
+
+
+ host#
+ bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
+
+ host#
+ route add -host 192.168.0.253 dev tap0
+
+
+
+
+
+
+ host#
+ bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp'
+
+
+
+
+
+
+ host#
+ arp -Ds 192.168.0.253 eth0 pub
+
+
+
+
+ Note that this must be done every time the host boots - this configu-
+ ration is not stored across host reboots. So, it's probably a good
+ idea to stick it in an rc file. An even better idea would be a little
+ utility which reads the information from a config file and sets up
+ devices at boot time.
+
+ +o Rather than using up two IPs and ARPing for one of them, you can
+ also provide direct access to your LAN by the UML by using a
+ bridge.
+
+
+ host#
+ brctl addbr br0
+
+
+
+
+
+
+ host#
+ ifconfig eth0 0.0.0.0 promisc up
+
+
+
+
+
+
+ host#
+ ifconfig tap0 0.0.0.0 promisc up
+
+
+
+
+
+
+ host#
+ ifconfig br0 192.168.0.1 netmask 255.255.255.0 up
+
+
+
+
+
+
+
+ host#
+ brctl stp br0 off
+
+
+
+
+
+
+ host#
+ brctl setfd br0 1
+
+
+
+
+
+
+ host#
+ brctl sethello br0 1
+
+
+
+
+
+
+ host#
+ brctl addif br0 eth0
+
+
+
+
+
+
+ host#
+ brctl addif br0 tap0
+
+
+
+
+ Note that 'br0' should be setup using ifconfig with the existing IP
+ address of eth0, as eth0 no longer has its own IP.
+
+ +o
+
+
+ Also, the /dev/net/tun device must be writable by the user running
+ UML in order for the UML to use the device that's been configured
+ for it. The simplest thing to do is
+
+
+ host# chmod 666 /dev/net/tun
+
+
+
+
+ Making it world-writeable looks bad, but it seems not to be
+ exploitable as a security hole. However, it does allow anyone to cre-
+ ate useless tap devices (useless because they can't configure them),
+ which is a DOS attack. A somewhat more secure alternative would to be
+ to create a group containing all the users who have preconfigured tap
+ devices and chgrp /dev/net/tun to that group with mode 664 or 660.
+
+
+ +o Once the device is set up, run UML with 'eth0=tuntap,device name'
+ (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the
+ mconsole config command).
+
+ +o Bring the eth device up in UML and you're in business.
+
+ If you don't want that tap device any more, you can make it non-
+ persistent with
+
+
+ host# tunctl -d tap device
+
+
+
+
+ Finally, tunctl has a -b (for brief mode) switch which causes it to
+ output only the name of the tap device it created. This makes it
+ suitable for capture by a script:
+
+
+ host# TAP=`tunctl -u 1000 -b`
+
+
+
+
+
+
+ 66..88.. EEtthheerrttaapp
+
+ Ethertap is the general mechanism on 2.2 for userspace processes to
+ exchange packets with the kernel.
+
+
+
+ To use this transport, you need to describe the virtual network device
+ on the UML command line. The general format for this is
+
+
+ eth <n> =ethertap, <device> , <ethernet address> , <tap IP address>
+
+
+
+
+ So, the previous example
+
+
+ eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254
+
+
+
+
+ attaches the UML eth0 device to the host /dev/tap0, assigns it the
+ ethernet address fe:fd:0:0:0:1, and assigns the IP address
+ 192.168.0.254 to the tap device.
+
+
+
+ The tap device is mandatory, but the others are optional. If the
+ ethernet address is omitted, one will be assigned to it.
+
+
+ The presence of the tap IP address will cause the helper to run and do
+ whatever host setup is needed to allow the virtual machine to
+ communicate with the outside world. If you're not sure you know what
+ you're doing, this is the way to go.
+
+
+ If it is absent, then you must configure the tap device and whatever
+ arping and routing you will need on the host. However, even in this
+ case, the uml_net helper still needs to be in your path and it must be
+ setuid root if you're not running UML as root. This is because the
+ tap device doesn't support SIGIO, which UML needs in order to use
+ something as a source of input. So, the helper is used as a
+ convenient asynchronous IO thread.
+
+ If you're using the uml_net helper, you can ignore the following host
+ setup - uml_net will do it for you. You just need to make sure you
+ have ethertap available, either built in to the host kernel or
+ available as a module.
+
+
+ If you want to set things up yourself, you need to make sure that the
+ appropriate /dev entry exists. If it doesn't, become root and create
+ it as follows:
+
+
+ mknod /dev/tap <minor> c 36 <minor> + 16
+
+
+
+
+ For example, this is how to create /dev/tap0:
+
+
+ mknod /dev/tap0 c 36 0 + 16
+
+
+
+
+ You also need to make sure that the host kernel has ethertap support.
+ If ethertap is enabled as a module, you apparently need to insmod
+ ethertap once for each ethertap device you want to enable. So,
+
+
+ host#
+ insmod ethertap
+
+
+
+
+ will give you the tap0 interface. To get the tap1 interface, you need
+ to run
+
+
+ host#
+ insmod ethertap unit=1 -o ethertap1
+
+
+
+
+
+
+
+ 66..99.. TThhee sswwiittcchh ddaaeemmoonn
+
+ NNoottee: This is the daemon formerly known as uml_router, but which was
+ renamed so the network weenies of the world would stop growling at me.
+
+
+ The switch daemon, uml_switch, provides a mechanism for creating a
+ totally virtual network. By default, it provides no connection to the
+ host network (but see -tap, below).
+
+
+ The first thing you need to do is run the daemon. Running it with no
+ arguments will make it listen on a default pair of unix domain
+ sockets.
+
+
+ If you want it to listen on a different pair of sockets, use
+
+
+ -unix control socket data socket
+
+
+
+
+
+ If you want it to act as a hub rather than a switch, use
+
+
+ -hub
+
+
+
+
+
+ If you want the switch to be connected to host networking (allowing
+ the umls to get access to the outside world through the host), use
+
+
+ -tap tap0
+
+
+
+
+
+ Note that the tap device must be preconfigured (see "TUN/TAP with a
+ preconfigured tap device", above). If you're using a different tap
+ device than tap0, specify that instead of tap0.
+
+
+ uml_switch can be backgrounded as follows
+
+
+ host%
+ uml_switch [ options ] < /dev/null > /dev/null
+
+
+
+
+ The reason it doesn't background by default is that it listens to
+ stdin for EOF. When it sees that, it exits.
+
+
+ The general format of the kernel command line switch is
+
+
+
+ ethn=daemon,ethernet address,socket
+ type,control socket,data socket
+
+
+
+
+ You can leave off everything except the 'daemon'. You only need to
+ specify the ethernet address if the one that will be assigned to it
+ isn't acceptable for some reason. The rest of the arguments describe
+ how to communicate with the daemon. You should only specify them if
+ you told the daemon to use different sockets than the default. So, if
+ you ran the daemon with no arguments, running the UML on the same
+ machine with
+ eth0=daemon
+
+
+
+
+ will cause the eth0 driver to attach itself to the daemon correctly.
+
+
+
+ 66..1100.. SSlliipp
+
+ Slip is another, less general, mechanism for a process to communicate
+ with the host networking. In contrast to the ethertap interface,
+ which exchanges ethernet frames with the host and can be used to
+ transport any higher-level protocol, it can only be used to transport
+ IP.
+
+
+ The general format of the command line switch is
+
+
+
+ ethn=slip,slip IP
+
+
+
+
+ The slip IP argument is the IP address that will be assigned to the
+ host end of the slip device. If it is specified, the helper will run
+ and will set up the host so that the virtual machine can reach it and
+ the rest of the network.
+
+
+ There are some oddities with this interface that you should be aware
+ of. You should only specify one slip device on a given virtual
+ machine, and its name inside UML will be 'umn', not 'eth0' or whatever
+ you specified on the command line. These problems will be fixed at
+ some point.
+
+
+
+ 66..1111.. SSlliirrpp
+
+ slirp uses an external program, usually /usr/bin/slirp, to provide IP
+ only networking connectivity through the host. This is similar to IP
+ masquerading with a firewall, although the translation is performed in
+ user-space, rather than by the kernel. As slirp does not set up any
+ interfaces on the host, or changes routing, slirp does not require
+ root access or setuid binaries on the host.
+
+
+ The general format of the command line switch for slirp is:
+
+
+
+ ethn=slirp,ethernet address,slirp path
+
+
+
+
+ The ethernet address is optional, as UML will set up the interface
+ with an ethernet address based upon the initial IP address of the
+ interface. The slirp path is generally /usr/bin/slirp, although it
+ will depend on distribution.
+
+
+ The slirp program can have a number of options passed to the command
+ line and we can't add them to the UML command line, as they will be
+ parsed incorrectly. Instead, a wrapper shell script can be written or
+ the options inserted into the /.slirprc file. More information on
+ all of the slirp options can be found in its man pages.
+
+
+ The eth0 interface on UML should be set up with the IP 10.2.0.15,
+ although you can use anything as long as it is not used by a network
+ you will be connecting to. The default route on UML should be set to
+ use
+
+
+ UML#
+ route add default dev eth0
+
+
+
+
+ slirp provides a number of useful IP addresses which can be used by
+ UML, such as 10.0.2.3 which is an alias for the DNS server specified
+ in /etc/resolv.conf on the host or the IP given in the 'dns' option
+ for slirp.
+
+
+ Even with a baudrate setting higher than 115200, the slirp connection
+ is limited to 115200. If you need it to go faster, the slirp binary
+ needs to be compiled with FULL_BOLT defined in config.h.
+
+
+
+ 66..1122.. ppccaapp
+
+ The pcap transport is attached to a UML ethernet device on the command
+ line or with uml_mconsole with the following syntax:
+
+
+
+ ethn=pcap,host interface,filter
+ expression,option1,option2
+
+
+
+
+ The expression and options are optional.
+
+
+ The interface is whatever network device on the host you want to
+ sniff. The expression is a pcap filter expression, which is also what
+ tcpdump uses, so if you know how to specify tcpdump filters, you will
+ use the same expressions here. The options are up to two of
+ 'promisc', control whether pcap puts the host interface into
+ promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap
+ expression optimizer is used.
+
+
+ Example:
+
+
+
+ eth0=pcap,eth0,tcp
+
+ eth1=pcap,eth0,!tcp
+
+
+
+ will cause the UML eth0 to emit all tcp packets on the host eth0 and
+ the UML eth1 to emit all non-tcp packets on the host eth0.
+
+
+
+ 66..1133.. SSeettttiinngg uupp tthhee hhoosstt yyoouurrsseellff
+
+ If you don't specify an address for the host side of the ethertap or
+ slip device, UML won't do any setup on the host. So this is what is
+ needed to get things working (the examples use a host-side IP of
+ 192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your
+ own network):
+
+ +o The device needs to be configured with its IP address. Tap devices
+ are also configured with an mtu of 1484. Slip devices are
+ configured with a point-to-point address pointing at the UML ip
+ address.
+
+
+ host# ifconfig tap0 arp mtu 1484 192.168.0.251 up
+
+
+
+
+
+
+ host#
+ ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up
+
+
+
+
+
+ +o If a tap device is being set up, a route is set to the UML IP.
+
+
+ UML# route add -host 192.168.0.250 gw 192.168.0.251
+
+
+
+
+
+ +o To allow other hosts on your network to see the virtual machine,
+ proxy arp is set up for it.
+
+
+ host# arp -Ds 192.168.0.250 eth0 pub
+
+
+
+
+
+ +o Finally, the host is set up to route packets.
+
+
+ host# echo 1 > /proc/sys/net/ipv4/ip_forward
+
+
+
+
+
+
+
+
+
+
+ 77.. SShhaarriinngg FFiilleessyysstteemmss bbeettwweeeenn VViirrttuuaall MMaacchhiinneess
+
+
+
+
+ 77..11.. AA wwaarrnniinngg
+
+ Don't attempt to share filesystems simply by booting two UMLs from the
+ same file. That's the same thing as booting two physical machines
+ from a shared disk. It will result in filesystem corruption.
+
+
+
+ 77..22.. UUssiinngg llaayyeerreedd bblloocckk ddeevviicceess
+
+ The way to share a filesystem between two virtual machines is to use
+ the copy-on-write (COW) layering capability of the ubd block driver.
+ As of 2.4.6-2um, the driver supports layering a read-write private
+ device over a read-only shared device. A machine's writes are stored
+ in the private device, while reads come from either device - the
+ private one if the requested block is valid in it, the shared one if
+ not. Using this scheme, the majority of data which is unchanged is
+ shared between an arbitrary number of virtual machines, each of which
+ has a much smaller file containing the changes that it has made. With
+ a large number of UMLs booting from a large root filesystem, this
+ leads to a huge disk space saving. It will also help performance,
+ since the host will be able to cache the shared data using a much
+ smaller amount of memory, so UML disk requests will be served from the
+ host's memory rather than its disks.
+
+
+
+
+ To add a copy-on-write layer to an existing block device file, simply
+ add the name of the COW file to the appropriate ubd switch:
+
+
+ ubd0=root_fs_cow,root_fs_debian_22
+
+
+
+
+ where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is
+ the existing shared filesystem. The COW file need not exist. If it
+ doesn't, the driver will create and initialize it. Once the COW file
+ has been initialized, it can be used on its own on the command line:
+
+
+ ubd0=root_fs_cow
+
+
+
+
+ The name of the backing file is stored in the COW file header, so it
+ would be redundant to continue specifying it on the command line.
+
+
+
+ 77..33.. NNoottee!!
+
+ When checking the size of the COW file in order to see the gobs of
+ space that you're saving, make sure you use 'ls -ls' to see the actual
+ disk consumption rather than the length of the file. The COW file is
+ sparse, so the length will be very different from the disk usage.
+ Here is a 'ls -l' of a COW file and backing file from one boot and
+ shutdown:
+ host% ls -l cow.debian debian2.2
+ -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian
+ -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2
+
+
+
+
+ Doesn't look like much saved space, does it? Well, here's 'ls -ls':
+
+
+ host% ls -ls cow.debian debian2.2
+ 880 -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian
+ 525832 -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2
+
+
+
+
+ Now, you can see that the COW file has less than a meg of disk, rather
+ than 492 meg.
+
+
+
+ 77..44.. AAnnootthheerr wwaarrnniinngg
+
+ Once a filesystem is being used as a readonly backing file for a COW
+ file, do not boot directly from it or modify it in any way. Doing so
+ will invalidate any COW files that are using it. The mtime and size
+ of the backing file are stored in the COW file header at its creation,
+ and they must continue to match. If they don't, the driver will
+ refuse to use the COW file.
+
+
+
+
+ If you attempt to evade this restriction by changing either the
+ backing file or the COW header by hand, you will get a corrupted
+ filesystem.
+
+
+
+
+ Among other things, this means that upgrading the distribution in a
+ backing file and expecting that all of the COW files using it will see
+ the upgrade will not work.
+
+
+
+
+ 77..55.. uummll__mmoooo :: MMeerrggiinngg aa CCOOWW ffiillee wwiitthh iittss bbaacckkiinngg ffiillee
+
+ Depending on how you use UML and COW devices, it may be advisable to
+ merge the changes in the COW file into the backing file every once in
+ a while.
+
+
+
+
+ The utility that does this is uml_moo. Its usage is
+
+
+ host% uml_moo COW file new backing file
+
+
+
+
+ There's no need to specify the backing file since that information is
+ already in the COW file header. If you're paranoid, boot the new
+ merged file, and if you're happy with it, move it over the old backing
+ file.
+
+
+
+
+ uml_moo creates a new backing file by default as a safety measure. It
+ also has a destructive merge option which will merge the COW file
+ directly into its current backing file. This is really only usable
+ when the backing file only has one COW file associated with it. If
+ there are multiple COWs associated with a backing file, a -d merge of
+ one of them will invalidate all of the others. However, it is
+ convenient if you're short of disk space, and it should also be
+ noticably faster than a non-destructive merge.
+
+
+
+
+ uml_moo is installed with the UML deb and RPM. If you didn't install
+ UML from one of those packages, you can also get it from the UML
+ utilities <http://user-mode-linux.sourceforge.net/dl-sf.html#UML
+ utilities> tar file in tools/moo.
+
+
+
+
+
+
+
+
+ 88.. CCrreeaattiinngg ffiilleessyysstteemmss
+
+
+ You may want to create and mount new UML filesystems, either because
+ your root filesystem isn't large enough or because you want to use a
+ filesystem other than ext2.
+
+
+ This was written on the occasion of reiserfs being included in the
+ 2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will
+ talk about reiserfs. This information is generic, and the examples
+ should be easy to translate to the filesystem of your choice.
+
+
+ 88..11.. CCrreeaattee tthhee ffiilleessyysstteemm ffiillee
+
+ dd is your friend. All you need to do is tell dd to create an empty
+ file of the appropriate size. I usually make it sparse to save time
+ and to avoid allocating disk space until it's actually used. For
+ example, the following command will create a sparse 100 meg file full
+ of zeroes.
+
+
+ host%
+ dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M
+
+
+
+
+
+
+ 88..22.. AAssssiiggnn tthhee ffiillee ttoo aa UUMMLL ddeevviiccee
+
+ Add an argument like the following to the UML command line:
+
+ ubd4=new_filesystem
+
+
+
+
+ making sure that you use an unassigned ubd device number.
+
+
+
+ 88..33.. CCrreeaattiinngg aanndd mmoouunnttiinngg tthhee ffiilleessyysstteemm
+
+ Make sure that the filesystem is available, either by being built into
+ the kernel, or available as a module, then boot up UML and log in. If
+ the root filesystem doesn't have the filesystem utilities (mkfs, fsck,
+ etc), then get them into UML by way of the net or hostfs.
+
+
+ Make the new filesystem on the device assigned to the new file:
+
+
+ host# mkreiserfs /dev/ubd/4
+
+
+ <----------- MKREISERFSv2 ----------->
+
+ ReiserFS version 3.6.25
+ Block size 4096 bytes
+ Block count 25856
+ Used blocks 8212
+ Journal - 8192 blocks (18-8209), journal header is in block 8210
+ Bitmaps: 17
+ Root block 8211
+ Hash function "r5"
+ ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y
+ journal size 8192 (from 18)
+ Initializing journal - 0%....20%....40%....60%....80%....100%
+ Syncing..done.
+
+
+
+
+ Now, mount it:
+
+
+ UML#
+ mount /dev/ubd/4 /mnt
+
+
+
+
+ and you're in business.
+
+
+
+
+
+
+
+
+
+ 99.. HHoosstt ffiillee aacccceessss
+
+
+ If you want to access files on the host machine from inside UML, you
+ can treat it as a separate machine and either nfs mount directories
+ from the host or copy files into the virtual machine with scp or rcp.
+ However, since UML is running on the the host, it can access those
+ files just like any other process and make them available inside the
+ virtual machine without needing to use the network.
+
+
+ This is now possible with the hostfs virtual filesystem. With it, you
+ can mount a host directory into the UML filesystem and access the
+ files contained in it just as you would on the host.
+
+
+ 99..11.. UUssiinngg hhoossttffss
+
+ To begin with, make sure that hostfs is available inside the virtual
+ machine with
+
+
+ UML# cat /proc/filesystems
+
+
+
+ . hostfs should be listed. If it's not, either rebuild the kernel
+ with hostfs configured into it or make sure that hostfs is built as a
+ module and available inside the virtual machine, and insmod it.
+
+
+ Now all you need to do is run mount:
+
+
+ UML# mount none /mnt/host -t hostfs
+
+
+
+
+ will mount the host's / on the virtual machine's /mnt/host.
+
+
+ If you don't want to mount the host root directory, then you can
+ specify a subdirectory to mount with the -o switch to mount:
+
+
+ UML# mount none /mnt/home -t hostfs -o /home
+
+
+
+
+ will mount the hosts's /home on the virtual machine's /mnt/home.
+
+
+
+ 99..22.. hhoossttffss aass tthhee rroooott ffiilleessyysstteemm
+
+ It's possible to boot from a directory hierarchy on the host using
+ hostfs rather than using the standard filesystem in a file.
+
+ To start, you need that hierarchy. The easiest way is to loop mount
+ an existing root_fs file:
+
+
+ host# mount root_fs uml_root_dir -o loop
+
+
+
+
+ You need to change the filesystem type of / in etc/fstab to be
+ 'hostfs', so that line looks like this:
+
+ /dev/ubd/0 / hostfs defaults 1 1
+
+
+
+
+ Then you need to chown to yourself all the files in that directory
+ that are owned by root. This worked for me:
+
+
+ host# find . -uid 0 -exec chown jdike {} \;
+
+
+
+
+ Next, make sure that your UML kernel has hostfs compiled in, not as a
+ module. Then run UML with the boot device pointing at that directory:
+
+
+ ubd0=/path/to/uml/root/directory
+
+
+
+
+ UML should then boot as it does normally.
+
+
+ 99..33.. BBuuiillddiinngg hhoossttffss
+
+ If you need to build hostfs because it's not in your kernel, you have
+ two choices:
+
+
+
+ +o Compiling hostfs into the kernel:
+
+
+ Reconfigure the kernel and set the 'Host filesystem' option under
+
+
+ +o Compiling hostfs as a module:
+
+
+ Reconfigure the kernel and set the 'Host filesystem' option under
+ be in arch/um/fs/hostfs/hostfs.o. Install that in
+ /lib/modules/`uname -r`/fs in the virtual machine, boot it up, and
+
+
+ UML# insmod hostfs
+
+
+
+
+
+
+
+
+
+
+
+
+ 1100.. TThhee MMaannaaggeemmeenntt CCoonnssoollee
+
+
+
+ The UML management console is a low-level interface to the kernel,
+ somewhat like the i386 SysRq interface. Since there is a full-blown
+ operating system under UML, there is much greater flexibility possible
+ than with the SysRq mechanism.
+
+
+ There are a number of things you can do with the mconsole interface:
+
+ +o get the kernel version
+
+ +o add and remove devices
+
+ +o halt or reboot the machine
+
+ +o Send SysRq commands
+
+ +o Pause and resume the UML
+
+
+ You need the mconsole client (uml_mconsole) which is present in CVS
+ (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in
+ 2.4.6.
+
+
+ You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML.
+ When you boot UML, you'll see a line like:
+
+
+ mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole
+
+
+
+
+ If you specify a unique machine id one the UML command line, i.e.
+
+
+ umid=debian
+
+
+
+
+ you'll see this
+
+
+ mconsole initialized on /home/jdike/.uml/debian/mconsole
+
+
+
+
+ That file is the socket that uml_mconsole will use to communicate with
+ UML. Run it with either the umid or the full path as its argument:
+
+
+ host% uml_mconsole debian
+
+
+
+
+ or
+
+
+ host% uml_mconsole /home/jdike/.uml/debian/mconsole
+
+
+
+
+ You'll get a prompt, at which you can run one of these commands:
+
+ +o version
+
+ +o halt
+
+ +o reboot
+
+ +o config
+
+ +o remove
+
+ +o sysrq
+
+ +o help
+
+ +o cad
+
+ +o stop
+
+ +o go
+
+
+ 1100..11.. vveerrssiioonn
+
+ This takes no arguments. It prints the UML version.
+
+
+ (mconsole) version
+ OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686
+
+
+
+
+ There are a couple actual uses for this. It's a simple no-op which
+ can be used to check that a UML is running. It's also a way of
+ sending an interrupt to the UML. This is sometimes useful on SMP
+ hosts, where there's a bug which causes signals to UML to be lost,
+ often causing it to appear to hang. Sending such a UML the mconsole
+ version command is a good way to 'wake it up' before networking has
+ been enabled, as it does not do anything to the function of the UML.
+
+
+
+ 1100..22.. hhaalltt aanndd rreebboooott
+
+ These take no arguments. They shut the machine down immediately, with
+ no syncing of disks and no clean shutdown of userspace. So, they are
+ pretty close to crashing the machine.
+
+
+ (mconsole) halt
+ OK
+
+
+
+
+
+
+ 1100..33.. ccoonnffiigg
+
+ "config" adds a new device to the virtual machine. Currently the ubd
+ and network drivers support this. It takes one argument, which is the
+ device to add, with the same syntax as the kernel command line.
+
+
+
+
+ (mconsole)
+ config ubd3=/home/jdike/incoming/roots/root_fs_debian22
+
+ OK
+ (mconsole) config eth1=mcast
+ OK
+
+
+
+
+
+
+ 1100..44.. rreemmoovvee
+
+ "remove" deletes a device from the system. Its argument is just the
+ name of the device to be removed. The device must be idle in whatever
+ sense the driver considers necessary. In the case of the ubd driver,
+ the removed block device must not be mounted, swapped on, or otherwise
+ open, and in the case of the network driver, the device must be down.
+
+
+ (mconsole) remove ubd3
+ OK
+ (mconsole) remove eth1
+ OK
+
+
+
+
+
+
+ 1100..55.. ssyyssrrqq
+
+ This takes one argument, which is a single letter. It calls the
+ generic kernel's SysRq driver, which does whatever is called for by
+ that argument. See the SysRq documentation in Documentation/sysrq.txt
+ in your favorite kernel tree to see what letters are valid and what
+ they do.
+
+
+
+ 1100..66.. hheellpp
+
+ "help" returns a string listing the valid commands and what each one
+ does.
+
+
+
+ 1100..77.. ccaadd
+
+ This invokes the Ctl-Alt-Del action on init. What exactly this ends
+ up doing is up to /etc/inittab. Normally, it reboots the machine.
+ With UML, this is usually not desired, so if a halt would be better,
+ then find the section of inittab that looks like this
+
+
+ # What to do when CTRL-ALT-DEL is pressed.
+ ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
+
+
+
+
+ and change the command to halt.
+
+
+
+ 1100..88.. ssttoopp
+
+ This puts the UML in a loop reading mconsole requests until a 'go'
+ mconsole command is recieved. This is very useful for making backups
+ of UML filesystems, as the UML can be stopped, then synced via 'sysrq
+ s', so that everything is written to the filesystem. You can then copy
+ the filesystem and then send the UML 'go' via mconsole.
+
+
+ Note that a UML running with more than one CPU will have problems
+ after you send the 'stop' command, as only one CPU will be held in a
+ mconsole loop and all others will continue as normal. This is a bug,
+ and will be fixed.
+
+
+
+ 1100..99.. ggoo
+
+ This resumes a UML after being paused by a 'stop' command. Note that
+ when the UML has resumed, TCP connections may have timed out and if
+ the UML is paused for a long period of time, crond might go a little
+ crazy, running all the jobs it didn't do earlier.
+
+
+
+
+
+
+
+
+ 1111.. KKeerrnneell ddeebbuuggggiinngg
+
+
+ NNoottee:: The interface that makes debugging, as described here, possible
+ is present in 2.4.0-test6 kernels and later.
+
+
+ Since the user-mode kernel runs as a normal Linux process, it is
+ possible to debug it with gdb almost like any other process. It is
+ slightly different because the kernel's threads are already being
+ ptraced for system call interception, so gdb can't ptrace them.
+ However, a mechanism has been added to work around that problem.
+
+
+ In order to debug the kernel, you need build it from source. See
+ ``Compiling the kernel and modules'' for information on doing that.
+ Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during
+ the config. These will compile the kernel with -g, and enable the
+ ptrace proxy so that gdb works with UML, respectively.
+
+
+
+
+ 1111..11.. SSttaarrttiinngg tthhee kkeerrnneell uunnddeerr ggddbb
+
+ You can have the kernel running under the control of gdb from the
+ beginning by putting 'debug' on the command line. You will get an
+ xterm with gdb running inside it. The kernel will send some commands
+ to gdb which will leave it stopped at the beginning of start_kernel.
+ At this point, you can get things going with 'next', 'step', or
+ 'cont'.
+
+
+ There is a transcript of a debugging session here <debug-
+ session.html> , with breakpoints being set in the scheduler and in an
+ interrupt handler.
+ 1111..22.. EExxaammiinniinngg sslleeeeppiinngg pprroocceesssseess
+
+ Not every bug is evident in the currently running process. Sometimes,
+ processes hang in the kernel when they shouldn't because they've
+ deadlocked on a semaphore or something similar. In this case, when
+ you ^C gdb and get a backtrace, you will see the idle thread, which
+ isn't very relevant.
+
+
+ What you want is the stack of whatever process is sleeping when it
+ shouldn't be. You need to figure out which process that is, which is
+ generally fairly easy. Then you need to get its host process id,
+ which you can do either by looking at ps on the host or at
+ task.thread.extern_pid in gdb.
+
+
+ Now what you do is this:
+
+ +o detach from the current thread
+
+
+ (UML gdb) det
+
+
+
+
+
+ +o attach to the thread you are interested in
+
+
+ (UML gdb) att <host pid>
+
+
+
+
+
+ +o look at its stack and anything else of interest
+
+
+ (UML gdb) bt
+
+
+
+
+ Note that you can't do anything at this point that requires that a
+ process execute, e.g. calling a function
+
+ +o when you're done looking at that process, reattach to the current
+ thread and continue it
+
+
+ (UML gdb)
+ att 1
+
+
+
+
+
+
+ (UML gdb)
+ c
+
+
+
+
+ Here, specifying any pid which is not the process id of a UML thread
+ will cause gdb to reattach to the current thread. I commonly use 1,
+ but any other invalid pid would work.
+
+
+
+ 1111..33.. RRuunnnniinngg dddddd oonn UUMMLL
+
+ ddd works on UML, but requires a special kludge. The process goes
+ like this:
+
+ +o Start ddd
+
+
+ host% ddd linux
+
+
+
+
+
+ +o With ps, get the pid of the gdb that ddd started. You can ask the
+ gdb to tell you, but for some reason that confuses things and
+ causes a hang.
+
+ +o run UML with 'debug=parent gdb-pid=<pid>' added to the command line
+ - it will just sit there after you hit return
+
+ +o type 'att 1' to the ddd gdb and you will see something like
+
+
+ 0xa013dc51 in __kill ()
+
+
+ (gdb)
+
+
+
+
+
+ +o At this point, type 'c', UML will boot up, and you can use ddd just
+ as you do on any other process.
+
+
+
+ 1111..44.. DDeebbuuggggiinngg mmoodduulleess
+
+ gdb has support for debugging code which is dynamically loaded into
+ the process. This support is what is needed to debug kernel modules
+ under UML.
+
+
+ Using that support is somewhat complicated. You have to tell gdb what
+ object file you just loaded into UML and where in memory it is. Then,
+ it can read the symbol table, and figure out where all the symbols are
+ from the load address that you provided. It gets more interesting
+ when you load the module again (i.e. after an rmmod). You have to
+ tell gdb to forget about all its symbols, including the main UML ones
+ for some reason, then load then all back in again.
+
+
+ There's an easy way and a hard way to do this. The easy way is to use
+ the umlgdb expect script written by Chandan Kudige. It basically
+ automates the process for you.
+
+
+ First, you must tell it where your modules are. There is a list in
+ the script that looks like this:
+ set MODULE_PATHS {
+ "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o"
+ "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o"
+ "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o"
+ }
+
+
+
+
+ You change that to list the names and paths of the modules that you
+ are going to debug. Then you run it from the toplevel directory of
+ your UML pool and it basically tells you what to do:
+
+
+
+
+ ******** GDB pid is 21903 ********
+ Start UML as: ./linux <kernel switches> debug gdb-pid=21903
+
+
+
+ GNU gdb 5.0rh-5 Red Hat Linux 7.1
+ Copyright 2001 Free Software Foundation, Inc.
+ GDB is free software, covered by the GNU General Public License, and you are
+ welcome to change it and/or distribute copies of it under certain conditions.
+ Type "show copying" to see the conditions.
+ There is absolutely no warranty for GDB. Type "show warranty" for details.
+ This GDB was configured as "i386-redhat-linux"...
+ (gdb) b sys_init_module
+ Breakpoint 1 at 0xa0011923: file module.c, line 349.
+ (gdb) att 1
+
+
+
+
+ After you run UML and it sits there doing nothing, you hit return at
+ the 'att 1' and continue it:
+
+
+ Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1
+ 0xa00f4221 in __kill ()
+ (UML gdb) c
+ Continuing.
+
+
+
+
+ At this point, you debug normally. When you insmod something, the
+ expect magic will kick in and you'll see something like:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *** Module hostfs loaded ***
+ Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs",
+ mod_user=0x8070e00) at module.c:349
+ 349 char *name, *n_name, *name_tmp = NULL;
+ (UML gdb) finish
+ Run till exit from #0 sys_init_module (name_user=0x805abb0 "hostfs",
+ mod_user=0x8070e00) at module.c:349
+ 0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411
+ 411 else res = EXECUTE_SYSCALL(syscall, regs);
+ Value returned is $1 = 0
+ (UML gdb)
+ p/x (int)module_list + module_list->size_of_struct
+
+ $2 = 0xa9021054
+ (UML gdb) symbol-file ./linux
+ Load new symbol table from "./linux"? (y or n) y
+ Reading symbols from ./linux...
+ done.
+ (UML gdb)
+ add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054
+
+ add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at
+ .text_addr = 0xa9021054
+ (y or n) y
+
+ Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o...
+ done.
+ (UML gdb) p *module_list
+ $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs",
+ size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1,
+ nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0,
+ init = 0xa90221f0 <init_hostfs>, cleanup = 0xa902222c <exit_hostfs>,
+ ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0,
+ persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0,
+ kallsyms_end = 0x0,
+ archdata_start = 0x1b855 <Address 0x1b855 out of bounds>,
+ archdata_end = 0xe5890000 <Address 0xe5890000 out of bounds>,
+ kernel_data = 0xf689c35d <Address 0xf689c35d out of bounds>}
+ >> Finished loading symbols for hostfs ...
+
+
+
+
+ That's the easy way. It's highly recommended. The hard way is
+ described below in case you're interested in what's going on.
+
+
+ Boot the kernel under the debugger and load the module with insmod or
+ modprobe. With gdb, do:
+
+
+ (UML gdb) p module_list
+
+
+
+
+ This is a list of modules that have been loaded into the kernel, with
+ the most recently loaded module first. Normally, the module you want
+ is at module_list. If it's not, walk down the next links, looking at
+ the name fields until find the module you want to debug. Take the
+ address of that structure, and add module.size_of_struct (which in
+ 2.4.10 kernels is 96 (0x60)) to it. Gdb can make this hard addition
+ for you :-):
+
+
+
+ (UML gdb)
+ printf "%#x\n", (int)module_list module_list->size_of_struct
+
+
+
+
+ The offset from the module start occasionally changes (before 2.4.0,
+ it was module.size_of_struct + 4), so it's a good idea to check the
+ init and cleanup addresses once in a while, as describe below. Now
+ do:
+
+
+ (UML gdb)
+ add-symbol-file /path/to/module/on/host that_address
+
+
+
+
+ Tell gdb you really want to do it, and you're in business.
+
+
+ If there's any doubt that you got the offset right, like breakpoints
+ appear not to work, or they're appearing in the wrong place, you can
+ check it by looking at the module structure. The init and cleanup
+ fields should look like:
+
+
+ init = 0x588066b0 <init_hostfs>, cleanup = 0x588066c0 <exit_hostfs>
+
+
+
+
+ with no offsets on the symbol names. If the names are right, but they
+ are offset, then the offset tells you how much you need to add to the
+ address you gave to add-symbol-file.
+
+
+ When you want to load in a new version of the module, you need to get
+ gdb to forget about the old one. The only way I've found to do that
+ is to tell gdb to forget about all symbols that it knows about:
+
+
+ (UML gdb) symbol-file
+
+
+
+
+ Then reload the symbols from the kernel binary:
+
+
+ (UML gdb) symbol-file /path/to/kernel
+
+
+
+
+ and repeat the process above. You'll also need to re-enable break-
+ points. They were disabled when you dumped all the symbols because
+ gdb couldn't figure out where they should go.
+
+
+
+ 1111..55.. AAttttaacchhiinngg ggddbb ttoo tthhee kkeerrnneell
+
+ If you don't have the kernel running under gdb, you can attach gdb to
+ it later by sending the tracing thread a SIGUSR1. The first line of
+ the console output identifies its pid:
+ tracing thread pid = 20093
+
+
+
+
+ When you send it the signal:
+
+
+ host% kill -USR1 20093
+
+
+
+
+ you will get an xterm with gdb running in it.
+
+
+ If you have the mconsole compiled into UML, then the mconsole client
+ can be used to start gdb:
+
+
+ (mconsole) (mconsole) config gdb=xterm
+
+
+
+
+ will fire up an xterm with gdb running in it.
+
+
+
+ 1111..66.. UUssiinngg aalltteerrnnaattee ddeebbuuggggeerrss
+
+ UML has support for attaching to an already running debugger rather
+ than starting gdb itself. This is present in CVS as of 17 Apr 2001.
+ I sent it to Alan for inclusion in the ac tree, and it will be in my
+ 2.4.4 release.
+
+
+ This is useful when gdb is a subprocess of some UI, such as emacs or
+ ddd. It can also be used to run debuggers other than gdb on UML.
+ Below is an example of using strace as an alternate debugger.
+
+
+ To do this, you need to get the pid of the debugger and pass it in
+ with the
+
+
+ If you are using gdb under some UI, then tell it to 'att 1', and
+ you'll find yourself attached to UML.
+
+
+ If you are using something other than gdb as your debugger, then
+ you'll need to get it to do the equivalent of 'att 1' if it doesn't do
+ it automatically.
+
+
+ An example of an alternate debugger is strace. You can strace the
+ actual kernel as follows:
+
+ +o Run the following in a shell
+
+
+ host%
+ sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out'
+
+
+
+ +o Run UML with 'debug' and 'gdb-pid=<pid>' with the pid printed out
+ by the previous command
+
+ +o Hit return in the shell, and UML will start running, and strace
+ output will start accumulating in the output file.
+
+ Note that this is different from running
+
+
+ host% strace ./linux
+
+
+
+
+ That will strace only the main UML thread, the tracing thread, which
+ doesn't do any of the actual kernel work. It just oversees the vir-
+ tual machine. In contrast, using strace as described above will show
+ you the low-level activity of the virtual machine.
+
+
+
+
+
+ 1122.. KKeerrnneell ddeebbuuggggiinngg eexxaammpplleess
+
+ 1122..11.. TThhee ccaassee ooff tthhee hhuunngg ffsscckk
+
+ When booting up the kernel, fsck failed, and dropped me into a shell
+ to fix things up. I ran fsck -y, which hung:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Setting hostname uml [ OK ]
+ Checking root filesystem
+ /dev/fhd0 was not cleanly unmounted, check forced.
+ Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.
+
+ /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
+ (i.e., without -a or -p options)
+ [ FAILED ]
+
+ *** An error occurred during the file system check.
+ *** Dropping you to a shell; the system will reboot
+ *** when you leave the shell.
+ Give root password for maintenance
+ (or type Control-D for normal startup):
+
+ [root@uml /root]# fsck -y /dev/fhd0
+ fsck -y /dev/fhd0
+ Parallelizing fsck version 1.14 (9-Jan-1999)
+ e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09
+ /dev/fhd0 contains a file system with errors, check forced.
+ Pass 1: Checking inodes, blocks, and sizes
+ Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes
+
+ Inode 19780, i_blocks is 1548, should be 540. Fix? yes
+
+ Pass 2: Checking directory structure
+ Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes
+
+ Directory inode 11858, block 0, offset 0: directory corrupted
+ Salvage? yes
+
+ Missing '.' in directory inode 11858.
+ Fix? yes
+
+ Missing '..' in directory inode 11858.
+ Fix? yes
+
+
+
+
+
+ The standard drill in this sort of situation is to fire up gdb on the
+ signal thread, which, in this case, was pid 1935. In another window,
+ I run gdb and attach pid 1935.
+
+
+
+
+ ~/linux/2.3.26/um 1016: gdb linux
+ GNU gdb 4.17.0.11 with Linux support
+ Copyright 1998 Free Software Foundation, Inc.
+ GDB is free software, covered by the GNU General Public License, and you are
+ welcome to change it and/or distribute copies of it under certain conditions.
+ Type "show copying" to see the conditions.
+ There is absolutely no warranty for GDB. Type "show warranty" for details.
+ This GDB was configured as "i386-redhat-linux"...
+
+ (gdb) att 1935
+ Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935
+ 0x100756d9 in __wait4 ()
+
+
+
+
+
+
+ Let's see what's currently running:
+
+
+
+ (gdb) p current_task.pid
+ $1 = 0
+
+
+
+
+
+ It's the idle thread, which means that fsck went to sleep for some
+ reason and never woke up.
+
+
+ Let's guess that the last process in the process list is fsck:
+
+
+
+ (gdb) p current_task.prev_task.comm
+ $13 = "fsck.ext2\000\000\000\000\000\000"
+
+
+
+
+
+ It is, so let's see what it thinks it's up to:
+
+
+
+ (gdb) p current_task.prev_task.thread
+ $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0,
+ kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = {
+ 3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720},
+ request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = {
+ regs = {1350467584, 2952789424, 0 <repeats 15 times>}, sigstack = 0,
+ pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000,
+ arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = {
+ op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}}
+
+
+
+
+
+ The interesting things here are the fact that its .thread.syscall.id
+ is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or
+ the defines in include/asm-um/arch/unistd.h), and that it never
+ returned. Also, its .request.op is OP_SWITCH (see
+ arch/um/include/user_util.h). These mean that it went into a write,
+ and, for some reason, called schedule().
+
+
+ The fact that it never returned from write means that its stack should
+ be fairly interesting. Its pid is 1980 (.thread.extern_pid). That
+ process is being ptraced by the signal thread, so it must be detached
+ before gdb can attach it:
+
+
+
+
+
+
+
+
+
+
+ (gdb) call detach(1980)
+
+ Program received signal SIGSEGV, Segmentation fault.
+ <function called from gdb>
+ The program being debugged stopped while in a function called from GDB.
+ When the function (detach) is done executing, GDB will silently
+ stop (instead of continuing to evaluate the expression containing
+ the function call).
+ (gdb) call detach(1980)
+ $15 = 0
+
+
+
+
+
+ The first detach segfaults for some reason, and the second one
+ succeeds.
+
+
+ Now I detach from the signal thread, attach to the fsck thread, and
+ look at its stack:
+
+
+ (gdb) det
+ Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935
+ (gdb) att 1980
+ Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980
+ 0x10070451 in __kill ()
+ (gdb) bt
+ #0 0x10070451 in __kill ()
+ #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30
+ #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000)
+ at process_kern.c:156
+ #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000)
+ at process_kern.c:161
+ #4 0x10001d12 in schedule () at sched.c:777
+ #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
+ #6 0x1006aa10 in __down_failed () at semaphore.c:157
+ #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174
+ #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
+ #9 <signal handler called>
+ #10 0x10155404 in errno ()
+ #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50
+ #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
+ #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
+ #14 <signal handler called>
+ #15 0xc0fd in ?? ()
+ #16 0x10016647 in sys_write (fd=3,
+ buf=0x80b8800 <Address 0x80b8800 out of bounds>, count=1024)
+ at read_write.c:159
+ #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08)
+ at syscall_kern.c:254
+ #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35
+ #19 <signal handler called>
+ #20 0x400dc8b0 in ?? ()
+
+
+
+
+
+ The interesting things here are :
+
+ +o There are two segfaults on this stack (frames 9 and 14)
+
+ +o The first faulting address (frame 11) is 0x50000800
+
+ (gdb) p (void *)1342179328
+ $16 = (void *) 0x50000800
+
+
+
+
+
+ The initial faulting address is interesting because it is on the idle
+ thread's stack. I had been seeing the idle thread segfault for no
+ apparent reason, and the cause looked like stack corruption. In hopes
+ of catching the culprit in the act, I had turned off all protections
+ to that stack while the idle thread wasn't running. This apparently
+ tripped that trap.
+
+
+ However, the more immediate problem is that second segfault and I'm
+ going to concentrate on that. First, I want to see where the fault
+ happened, so I have to go look at the sigcontent struct in frame 8:
+
+
+
+ (gdb) up
+ #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30
+ 30 kill(pid, SIGUSR1);
+ (gdb)
+ #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000)
+ at process_kern.c:156
+ 156 usr1_pid(getpid());
+ (gdb)
+ #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000)
+ at process_kern.c:161
+ 161 _switch_to(prev, next);
+ (gdb)
+ #4 0x10001d12 in schedule () at sched.c:777
+ 777 switch_to(prev, next, prev);
+ (gdb)
+ #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
+ 71 schedule();
+ (gdb)
+ #6 0x1006aa10 in __down_failed () at semaphore.c:157
+ 157 }
+ (gdb)
+ #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174
+ 174 segv(sc->cr2, sc->err & 2);
+ (gdb)
+ #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
+ 182 segv_handler(sc);
+ (gdb) p *sc
+ Cannot access memory at address 0x0.
+
+
+
+
+ That's not very useful, so I'll try a more manual method:
+
+
+ (gdb) p *((struct sigcontext *) (&sig + 1))
+ $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43,
+ __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440,
+ esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0,
+ trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118,
+ esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0,
+ cr2 = 1280}
+
+
+
+ The ip is in handle_mm_fault:
+
+
+ (gdb) p (void *)268480945
+ $20 = (void *) 0x1000b1b1
+ (gdb) i sym $20
+ handle_mm_fault + 57 in section .text
+
+
+
+
+
+ Specifically, it's in pte_alloc:
+
+
+ (gdb) i line *$20
+ Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b1b1 <handle_mm_fault+57>
+ and ends at 0x1000b1b7 <handle_mm_fault+63>.
+
+
+
+
+
+ To find where in handle_mm_fault this is, I'll jump forward in the
+ code until I see an address in that procedure:
+
+
+
+ (gdb) i line *0x1000b1c0
+ Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b1b7 <handle_mm_fault+63>
+ and ends at 0x1000b1c3 <handle_mm_fault+75>.
+ (gdb) i line *0x1000b1d0
+ Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b1d0 <handle_mm_fault+88>
+ and ends at 0x1000b1da <handle_mm_fault+98>.
+ (gdb) i line *0x1000b1e0
+ Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b1da <handle_mm_fault+98>
+ and ends at 0x1000b1e1 <handle_mm_fault+105>.
+ (gdb) i line *0x1000b1f0
+ Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b1f0 <handle_mm_fault+120>
+ and ends at 0x1000b200 <handle_mm_fault+136>.
+ (gdb) i line *0x1000b200
+ Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b200 <handle_mm_fault+136>
+ and ends at 0x1000b208 <handle_mm_fault+144>.
+ (gdb) i line *0x1000b210
+ Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
+ starts at address 0x1000b210 <handle_mm_fault+152>
+ and ends at 0x1000b219 <handle_mm_fault+161>.
+ (gdb) i line *0x1000b220
+ Line 1168 of "memory.c" starts at address 0x1000b21e <handle_mm_fault+166>
+ and ends at 0x1000b222 <handle_mm_fault+170>.
+
+
+
+
+
+ Something is apparently wrong with the page tables or vma_structs, so
+ lets go back to frame 11 and have a look at them:
+
+
+
+ #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50
+ 50 handle_mm_fault(current, vma, address, is_write);
+ (gdb) call pgd_offset_proc(vma->vm_mm, address)
+ $22 = (pgd_t *) 0x80a548c
+
+
+
+
+
+ That's pretty bogus. Page tables aren't supposed to be in process
+ text or data areas. Let's see what's in the vma:
+
+
+ (gdb) p *vma
+ $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640,
+ vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200,
+ vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000,
+ vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63,
+ vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec,
+ vm_private_data = 0x62}
+ (gdb) p *vma.vm_mm
+ $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000,
+ pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288},
+ map_count = 134909076, mmap_sem = {count = {counter = 135073792},
+ sleepers = -1342177872, wait = {lock = <optimized out or zero length>,
+ task_list = {next = 0xaffffe63, prev = 0xaffffe7a},
+ __magic = -1342177670, __creator = -1342177300}, __magic = 98},
+ page_table_lock = {}, context = 138, start_code = 0, end_code = 0,
+ start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0,
+ arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536,
+ total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0,
+ swap_address = 0, segments = 0x0}
+
+
+
+
+
+ This also pretty bogus. With all of the 0x80xxxxx and 0xaffffxxx
+ addresses, this is looking like a stack was plonked down on top of
+ these structures. Maybe it's a stack overflow from the next page:
+
+
+
+ (gdb) p vma
+ $25 = (struct vm_area_struct *) 0x507d2434
+
+
+
+
+
+ That's towards the lower quarter of the page, so that would have to
+ have been pretty heavy stack overflow:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (gdb) x/100x $25
+ 0x507d2434: 0x507d2434 0x00000000 0x08048000 0x080a4f8c
+ 0x507d2444: 0x00000000 0x080a79e0 0x080a8c94 0x080d1000
+ 0x507d2454: 0xaffffdb0 0xaffffe63 0xaffffe7a 0xaffffe7a
+ 0x507d2464: 0xafffffec 0x00000062 0x0000008a 0x00000000
+ 0x507d2474: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2484: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2494: 0x00000000 0x00000000 0x507d2fe0 0x00000000
+ 0x507d24a4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d24b4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d24c4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d24d4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d24e4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d24f4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2504: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2514: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2524: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2534: 0x00000000 0x00000000 0x507d25dc 0x00000000
+ 0x507d2544: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2554: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2564: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2574: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2584: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d2594: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d25a4: 0x00000000 0x00000000 0x00000000 0x00000000
+ 0x507d25b4: 0x00000000 0x00000000 0x00000000 0x00000000
+
+
+
+
+
+ It's not stack overflow. The only "stack-like" piece of this data is
+ the vma_struct itself.
+
+
+ At this point, I don't see any avenues to pursue, so I just have to
+ admit that I have no idea what's going on. What I will do, though, is
+ stick a trap on the segfault handler which will stop if it sees any
+ writes to the idle thread's stack. That was the thing that happened
+ first, and it may be that if I can catch it immediately, what's going
+ on will be somewhat clearer.
+
+
+ 1122..22.. EEppiissooddee 22:: TThhee ccaassee ooff tthhee hhuunngg ffsscckk
+
+ After setting a trap in the SEGV handler for accesses to the signal
+ thread's stack, I reran the kernel.
+
+
+ fsck hung again, this time by hitting the trap:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Setting hostname uml [ OK ]
+ Checking root filesystem
+ /dev/fhd0 contains a file system with errors, check forced.
+ Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.
+
+ /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
+ (i.e., without -a or -p options)
+ [ FAILED ]
+
+ *** An error occurred during the file system check.
+ *** Dropping you to a shell; the system will reboot
+ *** when you leave the shell.
+ Give root password for maintenance
+ (or type Control-D for normal startup):
+
+ [root@uml /root]# fsck -y /dev/fhd0
+ fsck -y /dev/fhd0
+ Parallelizing fsck version 1.14 (9-Jan-1999)
+ e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09
+ /dev/fhd0 contains a file system with errors, check forced.
+ Pass 1: Checking inodes, blocks, and sizes
+ Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes
+
+ Pass 2: Checking directory structure
+ Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes
+
+ Directory inode 11858, block 0, offset 0: directory corrupted
+ Salvage? yes
+
+ Missing '.' in directory inode 11858.
+ Fix? yes
+
+ Missing '..' in directory inode 11858.
+ Fix? yes
+
+ Untested (4127) [100fe44c]: trap_kern.c line 31
+
+
+
+
+
+ I need to get the signal thread to detach from pid 4127 so that I can
+ attach to it with gdb. This is done by sending it a SIGUSR1, which is
+ caught by the signal thread, which detaches the process:
+
+
+ kill -USR1 4127
+
+
+
+
+
+ Now I can run gdb on it:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ~/linux/2.3.26/um 1034: gdb linux
+ GNU gdb 4.17.0.11 with Linux support
+ Copyright 1998 Free Software Foundation, Inc.
+ GDB is free software, covered by the GNU General Public License, and you are
+ welcome to change it and/or distribute copies of it under certain conditions.
+ Type "show copying" to see the conditions.
+ There is absolutely no warranty for GDB. Type "show warranty" for details.
+ This GDB was configured as "i386-redhat-linux"...
+ (gdb) att 4127
+ Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127
+ 0x10075891 in __libc_nanosleep ()
+
+
+
+
+
+ The backtrace shows that it was in a write and that the fault address
+ (address in frame 3) is 0x50000800, which is right in the middle of
+ the signal thread's stack page:
+
+
+ (gdb) bt
+ #0 0x10075891 in __libc_nanosleep ()
+ #1 0x1007584d in __sleep (seconds=1000000)
+ at ../sysdeps/unix/sysv/linux/sleep.c:78
+ #2 0x1006ce9a in stop () at user_util.c:191
+ #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31
+ #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
+ #5 0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182
+ #6 <signal handler called>
+ #7 0xc0fd in ?? ()
+ #8 0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024)
+ at read_write.c:159
+ #9 0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08)
+ at syscall_kern.c:254
+ #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35
+ #11 <signal handler called>
+ #12 0x400dc8b0 in ?? ()
+ #13 <signal handler called>
+ #14 0x400dc8b0 in ?? ()
+ #15 0x80545fd in ?? ()
+ #16 0x804daae in ?? ()
+ #17 0x8054334 in ?? ()
+ #18 0x804d23e in ?? ()
+ #19 0x8049632 in ?? ()
+ #20 0x80491d2 in ?? ()
+ #21 0x80596b5 in ?? ()
+ (gdb) p (void *)1342179328
+ $3 = (void *) 0x50000800
+
+
+
+
+
+ Going up the stack to the segv_handler frame and looking at where in
+ the code the access happened shows that it happened near line 110 of
+ block_dev.c:
+
+
+
+
+
+
+
+
+
+ (gdb) up
+ #1 0x1007584d in __sleep (seconds=1000000)
+ at ../sysdeps/unix/sysv/linux/sleep.c:78
+ ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory.
+ (gdb)
+ #2 0x1006ce9a in stop () at user_util.c:191
+ 191 while(1) sleep(1000000);
+ (gdb)
+ #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31
+ 31 KERN_UNTESTED();
+ (gdb)
+ #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
+ 174 segv(sc->cr2, sc->err & 2);
+ (gdb) p *sc
+ $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43,
+ __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484,
+ esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14,
+ err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070,
+ esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0,
+ cr2 = 1342179328}
+ (gdb) p (void *)268550834
+ $2 = (void *) 0x1001c2b2
+ (gdb) i sym $2
+ block_write + 1090 in section .text
+ (gdb) i line *$2
+ Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h"
+ starts at address 0x1001c2a1 <block_write+1073>
+ and ends at 0x1001c2bf <block_write+1103>.
+ (gdb) i line *0x1001c2c0
+ Line 110 of "block_dev.c" starts at address 0x1001c2bf <block_write+1103>
+ and ends at 0x1001c2e3 <block_write+1139>.
+
+
+
+
+
+ Looking at the source shows that the fault happened during a call to
+ copy_to_user to copy the data into the kernel:
+
+
+ 107 count -= chars;
+ 108 copy_from_user(p,buf,chars);
+ 109 p += chars;
+ 110 buf += chars;
+
+
+
+
+
+ p is the pointer which must contain 0x50000800, since buf contains
+ 0x80b8800 (frame 8 above). It is defined as:
+
+
+ p = offset + bh->b_data;
+
+
+
+
+
+ I need to figure out what bh is, and it just so happens that bh is
+ passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a
+ few lines later, so I do a little disassembly:
+
+
+
+
+ (gdb) disas 0x1001c2bf 0x1001c2e0
+ Dump of assembler code from 0x1001c2bf to 0x1001c2d0:
+ 0x1001c2bf <block_write+1103>: addl %eax,0xc(%ebp)
+ 0x1001c2c2 <block_write+1106>: movl 0xfffffdd4(%ebp),%edx
+ 0x1001c2c8 <block_write+1112>: btsl $0x0,0x18(%edx)
+ 0x1001c2cd <block_write+1117>: btsl $0x1,0x18(%edx)
+ 0x1001c2d2 <block_write+1122>: sbbl %ecx,%ecx
+ 0x1001c2d4 <block_write+1124>: testl %ecx,%ecx
+ 0x1001c2d6 <block_write+1126>: jne 0x1001c2e3 <block_write+1139>
+ 0x1001c2d8 <block_write+1128>: pushl $0x0
+ 0x1001c2da <block_write+1130>: pushl %edx
+ 0x1001c2db <block_write+1131>: call 0x1001819c <__mark_buffer_dirty>
+ End of assembler dump.
+
+
+
+
+
+ At that point, bh is in %edx (address 0x1001c2da), which is calculated
+ at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is,
+ taking %ebp from the sigcontext_struct above:
+
+
+ (gdb) p (void *)1342631484
+ $5 = (void *) 0x5006ee3c
+ (gdb) p 0x5006ee3c+0xfffffdd4
+ $6 = 1342630928
+ (gdb) p (void *)$6
+ $7 = (void *) 0x5006ec10
+ (gdb) p *((void **)$7)
+ $8 = (void *) 0x50100200
+
+
+
+
+
+ Now, I look at the structure to see what's in it, and particularly,
+ what its b_data field contains:
+
+
+ (gdb) p *((struct buffer_head *)0x50100200)
+ $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0,
+ b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24,
+ b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260,
+ b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58,
+ b_data = 0x50000800 "", b_page = 0x50004000,
+ b_end_io = 0x10017f60 <end_buffer_io_sync>, b_dev_id = 0x0,
+ b_rsector = 98810, b_wait = {lock = <optimized out or zero length>,
+ task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448,
+ __creator = 0}, b_kiobuf = 0x0}
+
+
+
+
+
+ The b_data field is indeed 0x50000800, so the question becomes how
+ that happened. The rest of the structure looks fine, so this probably
+ is not a case of data corruption. It happened on purpose somehow.
+
+
+ The b_page field is a pointer to the page_struct representing the
+ 0x50000000 page. Looking at it shows the kernel's idea of the state
+ of that page:
+
+
+
+ (gdb) p *$13.b_page
+ $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0,
+ index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = {
+ next = 0x50008460, prev = 0x50019350}, wait = {
+ lock = <optimized out or zero length>, task_list = {next = 0x50004024,
+ prev = 0x50004024}, __magic = 1342193708, __creator = 0},
+ pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280,
+ zone = 0x100c5160}
+
+
+
+
+
+ Some sanity-checking: the virtual field shows the "virtual" address of
+ this page, which in this kernel is the same as its "physical" address,
+ and the page_struct itself should be mem_map[0], since it represents
+ the first page of memory:
+
+
+
+ (gdb) p (void *)1342177280
+ $18 = (void *) 0x50000000
+ (gdb) p mem_map
+ $19 = (mem_map_t *) 0x50004000
+
+
+
+
+
+ These check out fine.
+
+
+ Now to check out the page_struct itself. In particular, the flags
+ field shows whether the page is considered free or not:
+
+
+ (gdb) p (void *)132
+ $21 = (void *) 0x84
+
+
+
+
+
+ The "reserved" bit is the high bit, which is definitely not set, so
+ the kernel considers the signal stack page to be free and available to
+ be used.
+
+
+ At this point, I jump to conclusions and start looking at my early
+ boot code, because that's where that page is supposed to be reserved.
+
+
+ In my setup_arch procedure, I have the following code which looks just
+ fine:
+
+
+
+ bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn);
+ free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem);
+
+
+
+
+
+ Two stack pages have already been allocated, and low_physmem points to
+ the third page, which is the beginning of free memory.
+ The init_bootmem call declares the entire memory to the boot memory
+ manager, which marks it all reserved. The free_bootmem call frees up
+ all of it, except for the first two pages. This looks correct to me.
+
+
+ So, I decide to see init_bootmem run and make sure that it is marking
+ those first two pages as reserved. I never get that far.
+
+
+ Stepping into init_bootmem, and looking at bootmem_map before looking
+ at what it contains shows the following:
+
+
+
+ (gdb) p bootmem_map
+ $3 = (void *) 0x50000000
+
+
+
+
+
+ Aha! The light dawns. That first page is doing double duty as a
+ stack and as the boot memory map. The last thing that the boot memory
+ manager does is to free the pages used by its memory map, so this page
+ is getting freed even its marked as reserved.
+
+
+ The fix was to initialize the boot memory manager before allocating
+ those two stack pages, and then allocate them through the boot memory
+ manager. After doing this, and fixing a couple of subsequent buglets,
+ the stack corruption problem disappeared.
+
+
+
+
+
+ 1133.. WWhhaatt ttoo ddoo wwhheenn UUMMLL ddooeessnn''tt wwoorrkk
+
+
+
+
+ 1133..11.. SSttrraannggee ccoommppiillaattiioonn eerrrroorrss wwhheenn yyoouu bbuuiilldd ffrroomm ssoouurrccee
+
+ As of test11, it is necessary to have "ARCH=um" in the environment or
+ on the make command line for all steps in building UML, including
+ clean, distclean, or mrproper, config, menuconfig, or xconfig, dep,
+ and linux. If you forget for any of them, the i386 build seems to
+ contaminate the UML build. If this happens, start from scratch with
+
+
+ host%
+ make mrproper ARCH=um
+
+
+
+
+ and repeat the build process with ARCH=um on all the steps.
+
+
+ See ``Compiling the kernel and modules'' for more details.
+
+
+ Another cause of strange compilation errors is building UML in
+ /usr/src/linux. If you do this, the first thing you need to do is
+ clean up the mess you made. The /usr/src/linux/asm link will now
+ point to /usr/src/linux/asm-um. Make it point back to
+ /usr/src/linux/asm-i386. Then, move your UML pool someplace else and
+ build it there. Also see below, where a more specific set of symptoms
+ is described.
+
+
+
+ 1133..22.. UUMMLL hhaannggss oonn bboooott aafftteerr mmoouunnttiinngg ddeevvffss
+
+ The boot looks like this:
+
+
+ VFS: Mounted root (ext2 filesystem) readonly.
+ Mounted devfs on /dev
+
+
+
+
+ You're probably running a recent distribution on an old machine. I
+ saw this with the RH7.1 filesystem running on a Pentium. The shared
+ library loader, ld.so, was executing an instruction (cmove) which the
+ Pentium didn't support. That instruction was apparently added later.
+ If you run UML under the debugger, you'll see the hang caused by one
+ instruction causing an infinite SIGILL stream.
+
+
+ The fix is to boot UML on an older filesystem.
+
+
+
+ 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss--
+ tteemm
+
+ I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27.
+ Panics preceded by
+
+
+ Detaching pid nnnn
+
+
+
+ are diagnostic of this problem. This is a reiserfs bug which causes a
+ thread to occasionally read stale data from a mmapped page shared with
+ another thread. The fix is to upgrade the filesystem or to have /tmp
+ be an ext2 filesystem.
+
+
+
+ 1133..44.. TThhee ccoommppiillee ffaaiillss wwiitthh eerrrroorrss aabboouutt ccoonnfflliiccttiinngg ttyyppeess ffoorr
+ ''ooppeenn'',, ''dduupp'',, aanndd ''wwaaiittppiidd''
+
+ This happens when you build in /usr/src/linux. The UML build makes
+ the include/asm link point to include/asm-um. /usr/include/asm points
+ to /usr/src/linux/include/asm, so when that link gets moved, files
+ which need to include the asm-i386 versions of headers get the
+ incompatible asm-um versions. The fix is to move the include/asm link
+ back to include/asm-i386 and to do UML builds someplace else.
+
+
+
+ 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm
+
+ This seems to be a similar situation with the resierfs problem above.
+ Some versions of NFS seems not to handle mmap correctly, which UML
+ depends on. The workaround is have /tmp be non-NFS directory.
+
+
+ 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt
+
+ If you build UML with gprof support and, early in the boot, it does
+ this
+
+
+ kernel BUG at page_alloc.c:100!
+
+
+
+
+ you have a buggy gcc. You can work around the problem by removing
+ UM_FASTCALL from CFLAGS in arch/um/Makefile-i386. This will open up
+ another bug, but that one is fairly hard to reproduce.
+
+
+
+ 1133..77.. ssyyssllooggdd ddiieess wwiitthh aa SSIIGGTTEERRMM oonn ssttaarrttuupp
+
+ The exact boot error depends on the distribution that you're booting,
+ but Debian produces this:
+
+
+ /etc/rc2.d/S10sysklogd: line 49: 93 Terminated
+ start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD
+
+
+
+
+ This is a syslogd bug. There's a race between a parent process
+ installing a signal handler and its child sending the signal. See
+ this uml-devel post <http://www.geocrawler.com/lists/3/Source-
+ Forge/709/0/6612801> for the details.
+
+
+
+ 1133..88.. TTUUNN//TTAAPP nneettwwoorrkkiinngg ddooeessnn''tt wwoorrkk oonn aa 22..44 hhoosstt
+
+ There are a couple of problems which were
+ <http://www.geocrawler.com/lists/3/SourceForge/597/0/> name="pointed
+ out"> by Tim Robinson <timro at trkr dot net>
+
+ +o It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier.
+ The fix is to upgrade to something more recent and then read the
+ next item.
+
+ +o If you see
+
+
+ File descriptor in bad state
+
+
+
+ when you bring up the device inside UML, you have a header mismatch
+ between the original kernel and the upgraded one. Make /usr/src/linux
+ point at the new headers. This will only be a problem if you build
+ uml_net yourself.
+
+
+
+ 1133..99.. YYoouu ccaann nneettwwoorrkk ttoo tthhee hhoosstt bbuutt nnoott ttoo ootthheerr mmaacchhiinneess oonn tthhee
+ nneett
+
+ If you can connect to the host, and the host can connect to UML, but
+ you can not connect to any other machines, then you may need to enable
+ IP Masquerading on the host. Usually this is only experienced when
+ using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML
+ networking, rather than the public address space that your host is
+ connected to. UML does not enable IP Masquerading, so you will need
+ to create a static rule to enable it:
+
+
+ host%
+ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
+
+
+
+
+ Replace eth0 with the interface that you use to talk to the rest of
+ the world.
+
+
+ Documentation on IP Masquerading, and SNAT, can be found at
+ www.netfilter.org <http://www.netfilter.org> .
+
+
+ If you can reach the local net, but not the outside Internet, then
+ that is usually a routing problem. The UML needs a default route:
+
+
+ UML#
+ route add default gw gateway IP
+
+
+
+
+ The gateway IP can be any machine on the local net that knows how to
+ reach the outside world. Usually, this is the host or the local net-
+ work's gateway.
+
+
+ Occasionally, we hear from someone who can reach some machines, but
+ not others on the same net, or who can reach some ports on other
+ machines, but not others. These are usually caused by strange
+ firewalling somewhere between the UML and the other box. You track
+ this down by running tcpdump on every interface the packets travel
+ over and see where they disappear. When you find a machine that takes
+ the packets in, but does not send them onward, that's the culprit.
+
+
+
+ 1133..1100.. II hhaavvee nnoo rroooott aanndd II wwaanntt ttoo ssccrreeaamm
+
+ Thanks to Birgit Wahlich for telling me about this strange one. It
+ turns out that there's a limit of six environment variables on the
+ kernel command line. When that limit is reached or exceeded, argument
+ processing stops, which means that the 'root=' argument that UML
+ usually adds is not seen. So, the filesystem has no idea what the
+ root device is, so it panics.
+
+
+ The fix is to put less stuff on the command line. Glomming all your
+ setup variables into one is probably the best way to go.
+
+
+
+ 1133..1111.. UUMMLL bbuuiilldd ccoonnfflliicctt bbeettwweeeenn ppttrraaccee..hh aanndd uuccoonntteexxtt..hh
+
+ On some older systems, /usr/include/asm/ptrace.h and
+ /usr/include/sys/ucontext.h define the same names. So, when they're
+ included together, the defines from one completely mess up the parsing
+ of the other, producing errors like:
+ /usr/include/sys/ucontext.h:47: parse error before
+ `10'
+
+
+
+
+ plus a pile of warnings.
+
+
+ This is a libc botch, which has since been fixed, and I don't see any
+ way around it besides upgrading.
+
+
+
+ 1133..1122.. TThhee UUMMLL BBooggooMMiippss iiss eexxaaccttllyy hhaallff tthhee hhoosstt''ss BBooggooMMiippss
+
+ On i386 kernels, there are two ways of running the loop that is used
+ to calculate the BogoMips rating, using the TSC if it's there or using
+ a one-instruction loop. The TSC produces twice the BogoMips as the
+ loop. UML uses the loop, since it has nothing resembling a TSC, and
+ will get almost exactly the same BogoMips as a host using the loop.
+ However, on a host with a TSC, its BogoMips will be double the loop
+ BogoMips, and therefore double the UML BogoMips.
+
+
+
+ 1133..1133.. WWhheenn yyoouu rruunn UUMMLL,, iitt iimmmmeeddiiaatteellyy sseeggffaauullttss
+
+ If the host is configured with the 2G/2G address space split, that's
+ why. See ``UML on 2G/2G hosts'' for the details on getting UML to
+ run on your host.
+
+
+
+ 1133..1144.. xxtteerrmmss aappppeeaarr,, tthheenn iimmmmeeddiiaatteellyy ddiissaappppeeaarr
+
+ If you're running an up to date kernel with an old release of
+ uml_utilities, the port-helper program will not work properly, so
+ xterms will exit straight after they appear. The solution is to
+ upgrade to the latest release of uml_utilities. Usually this problem
+ occurs when you have installed a packaged release of UML then compiled
+ your own development kernel without upgrading the uml_utilities from
+ the source distribution.
+
+
+
+ 1133..1155.. AAnnyy ootthheerr ppaanniicc,, hhaanngg,, oorr ssttrraannggee bbeehhaavviioorr
+
+ If you're seeing truly strange behavior, such as hangs or panics that
+ happen in random places, or you try running the debugger to see what's
+ happening and it acts strangely, then it could be a problem in the
+ host kernel. If you're not running a stock Linus or -ac kernel, then
+ try that. An early version of the preemption patch and a 2.4.10 SuSE
+ kernel have caused very strange problems in UML.
+
+
+ Otherwise, let me know about it. Send a message to one of the UML
+ mailing lists - either the developer list - user-mode-linux-devel at
+ lists dot sourceforge dot net (subscription info) or the user list -
+ user-mode-linux-user at lists dot sourceforge do net (subscription
+ info), whichever you prefer. Don't assume that everyone knows about
+ it and that a fix is imminent.
+
+
+ If you want to be super-helpful, read ``Diagnosing Problems'' and
+ follow the instructions contained therein.
+ 1144.. DDiiaaggnnoossiinngg PPrroobblleemmss
+
+
+ If you get UML to crash, hang, or otherwise misbehave, you should
+ report this on one of the project mailing lists, either the developer
+ list - user-mode-linux-devel at lists dot sourceforge dot net
+ (subscription info) or the user list - user-mode-linux-user at lists
+ dot sourceforge dot net (subscription info). When you do, it is
+ likely that I will want more information. So, it would be helpful to
+ read the stuff below, do whatever is applicable in your case, and
+ report the results to the list.
+
+
+ For any diagnosis, you're going to need to build a debugging kernel.
+ The binaries from this site aren't debuggable. If you haven't done
+ this before, read about ``Compiling the kernel and modules'' and
+ ``Kernel debugging'' UML first.
+
+
+ 1144..11.. CCaassee 11 :: NNoorrmmaall kkeerrnneell ppaanniiccss
+
+ The most common case is for a normal thread to panic. To debug this,
+ you will need to run it under the debugger (add 'debug' to the command
+ line). An xterm will start up with gdb running inside it. Continue
+ it when it stops in start_kernel and make it crash. Now ^C gdb and
+
+
+ If the panic was a "Kernel mode fault", then there will be a segv
+ frame on the stack and I'm going to want some more information. The
+ stack might look something like this:
+
+
+ (UML gdb) backtrace
+ #0 0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0)
+ at ../sysdeps/unix/sysv/linux/sigprocmask.c:49
+ #1 0x10091411 in change_sig (signal=10, on=1) at process.c:218
+ #2 0x10094785 in timer_handler (sig=26) at time_kern.c:32
+ #3 0x1009bf38 in __restore ()
+ at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125
+ #4 0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0)
+ at trap_kern.c:66
+ #5 0x10095c04 in segv_handler (sig=11) at trap_user.c:285
+ #6 0x1009bf38 in __restore ()
+
+
+
+
+ I'm going to want to see the symbol and line information for the value
+ of ip in the segv frame. In this case, you would do the following:
+
+
+ (UML gdb) i sym 268849158
+
+
+
+
+ and
+
+
+ (UML gdb) i line *268849158
+
+
+
+
+ The reason for this is the __restore frame right above the segv_han-
+ dler frame is hiding the frame that actually segfaulted. So, I have
+ to get that information from the faulting ip.
+
+
+ 1144..22.. CCaassee 22 :: TTrraacciinngg tthhrreeaadd ppaanniiccss
+
+ The less common and more painful case is when the tracing thread
+ panics. In this case, the kernel debugger will be useless because it
+ needs a healthy tracing thread in order to work. The first thing to
+ do is get a backtrace from the tracing thread. This is done by
+ figuring out what its pid is, firing up gdb, and attaching it to that
+ pid. You can figure out the tracing thread pid by looking at the
+ first line of the console output, which will look like this:
+
+
+ tracing thread pid = 15851
+
+
+
+
+ or by running ps on the host and finding the line that looks like
+ this:
+
+
+ jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)]
+
+
+
+
+ If the panic was 'segfault in signals', then follow the instructions
+ above for collecting information about the location of the seg fault.
+
+
+ If the tracing thread flaked out all by itself, then send that
+ backtrace in and wait for our crack debugging team to fix the problem.
+
+
+ 1144..33.. CCaassee 33 :: TTrraacciinngg tthhrreeaadd ppaanniiccss ccaauusseedd bbyy ootthheerr tthhrreeaaddss
+
+ However, there are cases where the misbehavior of another thread
+ caused the problem. The most common panic of this type is:
+
+
+ wait_for_stop failed to wait for <pid> to stop with <signal number>
+
+
+
+
+ In this case, you'll need to get a backtrace from the process men-
+ tioned in the panic, which is complicated by the fact that the kernel
+ debugger is defunct and without some fancy footwork, another gdb can't
+ attach to it. So, this is how the fancy footwork goes:
+
+ In a shell:
+
+
+ host% kill -STOP pid
+
+
+
+
+ Run gdb on the tracing thread as described in case 2 and do:
+
+
+ (host gdb) call detach(pid)
+
+
+ If you get a segfault, do it again. It always works the second time.
+
+ Detach from the tracing thread and attach to that other thread:
+
+
+ (host gdb) detach
+
+
+
+
+
+
+ (host gdb) attach pid
+
+
+
+
+ If gdb hangs when attaching to that process, go back to a shell and
+ do:
+
+
+ host%
+ kill -CONT pid
+
+
+
+
+ And then get the backtrace:
+
+
+ (host gdb) backtrace
+
+
+
+
+
+ 1144..44.. CCaassee 44 :: HHaannggss
+
+ Hangs seem to be fairly rare, but they sometimes happen. When a hang
+ happens, we need a backtrace from the offending process. Run the
+ kernel debugger as described in case 1 and get a backtrace. If the
+ current process is not the idle thread, then send in the backtrace.
+ You can tell that it's the idle thread if the stack looks like this:
+
+
+ #0 0x100b1401 in __libc_nanosleep ()
+ #1 0x100a2885 in idle_sleep (secs=10) at time.c:122
+ #2 0x100a546f in do_idle () at process_kern.c:445
+ #3 0x100a5508 in cpu_idle () at process_kern.c:471
+ #4 0x100ec18f in start_kernel () at init/main.c:592
+ #5 0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71
+ #6 0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50
+
+
+
+
+ If this is the case, then some other process is at fault, and went to
+ sleep when it shouldn't have. Run ps on the host and figure out which
+ process should not have gone to sleep and stayed asleep. Then attach
+ to it with gdb and get a backtrace as described in case 3.
+
+
+
+
+
+
+ 1155.. TThhaannkkss
+
+
+ A number of people have helped this project in various ways, and this
+ page gives recognition where recognition is due.
+
+
+ If you're listed here and you would prefer a real link on your name,
+ or no link at all, instead of the despammed email address pseudo-link,
+ let me know.
+
+
+ If you're not listed here and you think maybe you should be, please
+ let me know that as well. I try to get everyone, but sometimes my
+ bookkeeping lapses and I forget about contributions.
+
+
+ 1155..11.. CCooddee aanndd DDooccuummeennttaattiioonn
+
+ Rusty Russell <rusty at linuxcare.com.au> -
+
+ +o wrote the HOWTO <http://user-mode-
+ linux.sourceforge.net/UserModeLinux-HOWTO.html>
+
+ +o prodded me into making this project official and putting it on
+ SourceForge
+
+ +o came up with the way cool UML logo <http://user-mode-
+ linux.sourceforge.net/uml-small.png>
+
+ +o redid the config process
+
+
+ Peter Moulder <reiter at netspace.net.au> - Fixed my config and build
+ processes, and added some useful code to the block driver
+
+
+ Bill Stearns <wstearns at pobox.com> -
+
+ +o HOWTO updates
+
+ +o lots of bug reports
+
+ +o lots of testing
+
+ +o dedicated a box (uml.ists.dartmouth.edu) to support UML development
+
+ +o wrote the mkrootfs script, which allows bootable filesystems of
+ RPM-based distributions to be cranked out
+
+ +o cranked out a large number of filesystems with said script
+
+
+ Jim Leu <jleu at mindspring.com> - Wrote the virtual ethernet driver
+ and associated usermode tools
+
+ Lars Brinkhoff <http://lars.nocrew.org/> - Contributed the ptrace
+ proxy from his own project <http://a386.nocrew.org/> to allow easier
+ kernel debugging
+
+
+ Andrea Arcangeli <andrea at suse.de> - Redid some of the early boot
+ code so that it would work on machines with Large File Support
+
+
+ Chris Emerson <http://www.chiark.greenend.org.uk/~cemerson/> - Did
+ the first UML port to Linux/ppc
+
+
+ Harald Welte <laforge at gnumonks.org> - Wrote the multicast
+ transport for the network driver
+
+
+ Jorgen Cederlof - Added special file support to hostfs
+
+
+ Greg Lonnon <glonnon at ridgerun dot com> - Changed the ubd driver
+ to allow it to layer a COW file on a shared read-only filesystem and
+ wrote the iomem emulation support
+
+
+ Henrik Nordstrom <http://hem.passagen.se/hno/> - Provided a variety
+ of patches, fixes, and clues
+
+
+ Lennert Buytenhek - Contributed various patches, a rewrite of the
+ network driver, the first implementation of the mconsole driver, and
+ did the bulk of the work needed to get SMP working again.
+
+
+ Yon Uriarte - Fixed the TUN/TAP network backend while I slept.
+
+
+ Adam Heath - Made a bunch of nice cleanups to the initialization code,
+ plus various other small patches.
+
+
+ Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and
+ is doing a real nice job of it. He also noticed and fixed a number of
+ actually and potentially exploitable security holes in uml_net. Plus
+ the occasional patch. I like patches.
+
+
+ James McMechan - James seems to have taken over maintenance of the ubd
+ driver and is doing a nice job of it.
+
+
+ Chandan Kudige - wrote the umlgdb script which automates the reloading
+ of module symbols.
+
+
+ Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers,
+ enabling UML processes to access audio devices on the host. He also
+ submitted patches for the slip transport and lots of other things.
+
+
+ David Coulson <http://davidcoulson.net> -
+
+ +o Set up the usermodelinux.org <http://usermodelinux.org> site,
+ which is a great way of keeping the UML user community on top of
+ UML goings-on.
+
+ +o Site documentation and updates
+
+ +o Nifty little UML management daemon UMLd
+ <http://uml.openconsultancy.com/umld/>
+
+ +o Lots of testing and bug reports
+
+
+
+
+ 1155..22.. FFlluusshhiinngg oouutt bbuuggss
+
+
+
+ +o Yuri Pudgorodsky
+
+ +o Gerald Britton
+
+ +o Ian Wehrman
+
+ +o Gord Lamb
+
+ +o Eugene Koontz
+
+ +o John H. Hartman
+
+ +o Anders Karlsson
+
+ +o Daniel Phillips
+
+ +o John Fremlin
+
+ +o Rainer Burgstaller
+
+ +o James Stevenson
+
+ +o Matt Clay
+
+ +o Cliff Jefferies
+
+ +o Geoff Hoff
+
+ +o Lennert Buytenhek
+
+ +o Al Viro
+
+ +o Frank Klingenhoefer
+
+ +o Livio Baldini Soares
+
+ +o Jon Burgess
+
+ +o Petru Paler
+
+ +o Paul
+
+ +o Chris Reahard
+
+ +o Sverker Nilsson
+
+ +o Gong Su
+
+ +o johan verrept
+
+ +o Bjorn Eriksson
+
+ +o Lorenzo Allegrucci
+
+ +o Muli Ben-Yehuda
+
+ +o David Mansfield
+
+ +o Howard Goff
+
+ +o Mike Anderson
+
+ +o John Byrne
+
+ +o Sapan J. Batia
+
+ +o Iris Huang
+
+ +o Jan Hudec
+
+ +o Voluspa
+
+
+
+
+ 1155..33.. BBuugglleettss aanndd cclleeaann--uuppss
+
+
+
+ +o Dave Zarzycki
+
+ +o Adam Lazur
+
+ +o Boria Feigin
+
+ +o Brian J. Murrell
+
+ +o JS
+
+ +o Roman Zippel
+
+ +o Wil Cooley
+
+ +o Ayelet Shemesh
+
+ +o Will Dyson
+
+ +o Sverker Nilsson
+
+ +o dvorak
+
+ +o v.naga srinivas
+
+ +o Shlomi Fish
+
+ +o Roger Binns
+
+ +o johan verrept
+
+ +o MrChuoi
+
+ +o Peter Cleve
+
+ +o Vincent Guffens
+
+ +o Nathan Scott
+
+ +o Patrick Caulfield
+
+ +o jbearce
+
+ +o Catalin Marinas
+
+ +o Shane Spencer
+
+ +o Zou Min
+
+
+ +o Ryan Boder
+
+ +o Lorenzo Colitti
+
+ +o Gwendal Grignou
+
+ +o Andre' Breiler
+
+ +o Tsutomu Yasuda
+
+
+
+ 1155..44.. CCaassee SSttuuddiieess
+
+
+ +o Jon Wright
+
+ +o William McEwan
+
+ +o Michael Richardson
+
+
+
+ 1155..55.. OOtthheerr ccoonnttrriibbuuttiioonnss
+
+
+ Bill Carr <Bill.Carr at compaq.com> made the Red Hat mkrootfs script
+ work with RH 6.2.
+
+ Michael Jennings <mikejen at hevanet.com> sent in some material which
+ is now gracing the top of the index page <http://user-mode-
+ linux.sourceforge.net/index.html> of this site.
+
+ SGI <http://www.sgi.com> (and more specifically Ralf Baechle <ralf at
+ uni-koblenz.de> ) gave me an account on oss.sgi.com
+ <http://www.oss.sgi.com> . The bandwidth there made it possible to
+ produce most of the filesystems available on the project download
+ page.
+
+ Laurent Bonnaud <Laurent.Bonnaud at inpg.fr> took the old grotty
+ Debian filesystem that I've been distributing and updated it to 2.2.
+ It is now available by itself here.
+
+ Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make
+ releases even when Sourceforge is broken.
+
+ Rodrigo de Castro looked at my broken pte code and told me what was
+ wrong with it, letting me fix a long-standing (several weeks) and
+ serious set of bugs.
+
+ Chris Reahard built a specialized root filesystem for running a DNS
+ server jailed inside UML. It's available from the download
+ <http://user-mode-linux.sourceforge.net/dl-sf.html> page in the Jail
+ Filesysems section.
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt
index 9e3b8fe50405..62d5860f324e 100644
--- a/Documentation/usb/hotplug.txt
+++ b/Documentation/usb/hotplug.txt
@@ -5,8 +5,8 @@ into the bus with power on. In most cases, users expect the devices to become
immediately usable. That means the system must do many things, including:
- Find a driver that can handle the device. That may involve
- loading a kernel module; newer drivers can use modutils to
- publish their device (and class) support to user utilities.
+ loading a kernel module; newer drivers can use module-init-tools
+ to publish their device (and class) support to user utilities.
- Bind a driver to that device. Bus frameworks do that using a
device driver's probe() routine.
@@ -76,15 +76,15 @@ user mode daemon to detect changes in system configuration.
Currently available policy agent implementations can load drivers for
modules, and can invoke driver-specific setup scripts. The newest ones
-leverage USB modutils support. Later agents might unload drivers.
+leverage USB module-init-tools support. Later agents might unload drivers.
USB MODUTILS SUPPORT
-Current versions of modutils will create a "modules.usbmap" file which
-contains the entries from each driver's MODULE_DEVICE_TABLE. Such files
-can be used by various user mode policy agents to make sure all the right
-driver modules get loaded, either at boot time or later.
+Current versions of module-init-tools will create a "modules.usbmap" file
+which contains the entries from each driver's MODULE_DEVICE_TABLE. Such
+files can be used by various user mode policy agents to make sure all the
+right driver modules get loaded, either at boot time or later.
See <linux/usb.h> for full information about such table entries; or look
at existing drivers. Each table entry describes one or more criteria to
diff --git a/Documentation/video4linux/README.cpia b/Documentation/video4linux/README.cpia
index 521ef795a647..c95e7bbc0fdf 100644
--- a/Documentation/video4linux/README.cpia
+++ b/Documentation/video4linux/README.cpia
@@ -51,9 +51,9 @@ CONFIG_VIDEO_DEV=m
CONFIG_VIDEO_CPIA=m
CONFIG_VIDEO_CPIA_PP=m
-For autoloading of all those modules you need to tell modutils some
-stuff. Add the following line to your modutils config-file
-(e.g. /etc/modules.conf or wherever your distribution does store that
+For autoloading of all those modules you need to tell module-init-tools
+some stuff. Add the following line to your module-init-tools config-file
+(e.g. /etc/modprobe.conf or wherever your distribution does store that
stuff):
options parport_pc io=0x378 irq=7 dma=3
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index b8510c8addb2..9aff927ee623 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -167,6 +167,13 @@ config MK7
some extended instructions, and passes appropriate optimization
flags to GCC.
+config MK8
+ bool "Opteron/Athlon64/Hammer/K8"
+ help
+ Select this for an AMD Opteron or Athlon64 Hammer-family processor. Enables
+ use of some extended instructions, and passes appropriate optimization
+ flags to GCC.
+
config MELAN
bool "Elan"
@@ -227,7 +234,7 @@ config X86_L1_CACHE_SHIFT
int
default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || M686 || M586MMX || M586TSC || M586
default "4" if MELAN || M486 || M386
- default "6" if MK7
+ default "6" if MK7 || MK8
default "7" if MPENTIUM4
config RWSEM_GENERIC_SPINLOCK
@@ -282,7 +289,7 @@ config X86_ALIGNMENT_16
config X86_GOOD_APIC
bool
- depends on MK7 || MPENTIUM4 || MPENTIUMIII || M686 || M586MMX
+ depends on MK7 || MPENTIUM4 || MPENTIUMIII || M686 || M586MMX || MK8
default y
config X86_INTEL_USERCOPY
@@ -292,7 +299,7 @@ config X86_INTEL_USERCOPY
config X86_USE_PPRO_CHECKSUM
bool
- depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || M686
+ depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || M686 || MK8
default y
config X86_USE_3DNOW
@@ -305,6 +312,16 @@ config X86_OOSTORE
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6
default y
+config X86_PREFETCH
+ bool
+ depends on MPENTIUMIII || MP4
+ default y
+
+config X86_SSE2
+ bool
+ depends on MK8 || MPENTIUM4
+ default y
+
config HUGETLB_PAGE
bool "Huge TLB Page Support"
help
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index ef293556b96c..6277bdd05469 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -38,6 +38,7 @@ cflags-$(CONFIG_MPENTIUMIII) += $(call check_gcc,-march=pentium3,-march=i686)
cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686)
cflags-$(CONFIG_MK6) += $(call check_gcc,-march=k6,-march=i586)
cflags-$(CONFIG_MK7) += $(call check_gcc,-march=athlon,-march=i686 -malign-functions=4)
+cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 -malign-functions=4))
cflags-$(CONFIG_MCRUSOE) += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0
cflags-$(CONFIG_MWINCHIPC6) += $(call check_gcc,-march=winchip-c6,-march=i586)
cflags-$(CONFIG_MWINCHIP2) += $(call check_gcc,-march=winchip2,-march=i586)
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 98936e86c9b8..73d1bbdbf43c 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -614,7 +614,8 @@ static int __init detect_init_APIC (void)
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
+ if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) ||
+ (boot_cpu_data.x86 == 15))
break;
goto no_apic;
case X86_VENDOR_INTEL:
diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c
index 294c78c9b534..1df54f5a7087 100644
--- a/arch/i386/kernel/cpu/mcheck/k7.c
+++ b/arch/i386/kernel/cpu/mcheck/k7.c
@@ -1,5 +1,5 @@
/*
- * Athlon specific Machine Check Exception Reporting
+ * Athlon/Hammer specific Machine Check Exception Reporting
*/
#include <linux/init.h>
@@ -82,6 +82,9 @@ void __init amd_mcheck_init(struct cpuinfo_x86 *c)
nr_mce_banks = l & 0xff;
for (i=0; i<nr_mce_banks; i++) {
+ /* Don't enable northbridge MCE by default on Hammer */
+ if (boot_cpu_data.x86_model == 15 && i == 4)
+ continue;
wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
}
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 46caa93519aa..5b82d52983db 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -574,7 +574,7 @@ static int __init mtrr_init(void)
query the width (in bits) of the physical
addressable memory on the Hammer family.
*/
- if (boot_cpu_data.x86 >= 7
+ if (boot_cpu_data.x86 == 15
&& (cpuid_eax(0x80000000) >= 0x80000008)) {
u32 phys_addr;
phys_addr = cpuid_eax(0x80000008) & 0xff;
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index fbae2c8deeaf..9eeaca1be2a1 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -123,7 +123,7 @@ static int __init setup_nmi_watchdog(char *str)
nmi_watchdog = nmi;
if ((nmi == NMI_LOCAL_APIC) &&
(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
- (boot_cpu_data.x86 == 6))
+ (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
nmi_watchdog = nmi;
/*
* We can enable the IO-APIC watchdog
@@ -294,7 +294,7 @@ void __pminit setup_apic_nmi_watchdog (void)
{
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 != 6)
+ if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
return;
setup_k7_watchdog();
break;
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 45c65d3a4efa..f33880c8f87b 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -233,6 +233,7 @@ int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
*cpu = OPROFILE_CPU_ATHLON;
break;
+#ifndef CONFIG_X86_64
case X86_VENDOR_INTEL:
/* Less than a P6-class processor */
if (family != 6)
@@ -248,6 +249,7 @@ int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
model = &op_ppro_spec;
break;
+#endif
default:
return 0;
diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
index b4aabede5531..722353a5b7ff 100644
--- a/arch/i386/oprofile/op_model_athlon.c
+++ b/arch/i386/oprofile/op_model_athlon.c
@@ -99,7 +99,7 @@ static int athlon_check_ctrs(unsigned int const cpu,
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(regs->eip, i, cpu);
+ oprofile_add_sample(instruction_pointer(regs), i, cpu);
CTR_WRITE(reset_value[i], msrs, i);
return 1;
}
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
index 0f00c4d1e924..cff299fb1461 100644
--- a/arch/i386/oprofile/op_model_ppro.c
+++ b/arch/i386/oprofile/op_model_ppro.c
@@ -94,7 +94,7 @@ static int ppro_check_ctrs(unsigned int const cpu,
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(regs->eip, i, cpu);
+ oprofile_add_sample(instruction_pointer(regs), i, cpu);
CTR_WRITE(reset_value[i], msrs, i);
return 1;
}
diff --git a/arch/i386/oprofile/timer_int.c b/arch/i386/oprofile/timer_int.c
index 1159b7597eef..d4f0c24d89d9 100644
--- a/arch/i386/oprofile/timer_int.c
+++ b/arch/i386/oprofile/timer_int.c
@@ -21,7 +21,7 @@ static int timer_notify(struct notifier_block * self, unsigned long val, void *
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
- oprofile_add_sample(regs->eip, 0, cpu);
+ oprofile_add_sample(instruction_pointer(regs), 0, cpu);
return 0;
}
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 59e449a9187f..82fb20e2b639 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -2070,48 +2070,6 @@ config HPDCA
If you want to use the internal "DCA" serial ports on an HP300
machine, say Y here.
-config SUN3X_ZS
- bool "Sun3/3x builtin serial support"
- depends on SUN3 || SUN3X
- help
- ZS refers to a type of asynchronous serial port built in to the Sun3
- and Sun3x workstations; if you have a Sun 3, you probably have
- these. Say 'Y' to support ZS ports directly. This option must be
- enabled in order to support the
- keyboard and mouse ports.
-
-config SUN_KEYBOARD
- bool
- depends on SUN3X_ZS
- default y
- help
- Say Y here to support the keyboard found on Sun 3 and 3x
- workstations. It can also be used support Sun Type-5 keyboards
- through an adaptor. See
- <http://www.suse.cz/development/input/adapters.html> and
- <http://sourceforge.net/projects/linuxconsole/> for details on the
- latter.
-
-config SUN_MOUSE
- bool
- depends on SUN3X_ZS
- default y
-
-config SBUS
- bool
- depends on SUN3X_ZS
- default y
-
-config SBUSCHAR
- bool
- depends on SUN3X_ZS
- default y
-
-config SUN_SERIAL
- bool
- depends on SUN3X_ZS
- default y
-
config MVME147_SCC
bool "SCC support for MVME147 serial ports"
depends on MVME147
@@ -2148,7 +2106,7 @@ config DN_SERIAL
config SERIAL_CONSOLE
bool "Support for serial port console"
- depends on (AMIGA || ATARI || MAC || HP300 || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || HPDCA=y || SUN3X_ZS || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
+ depends on (AMIGA || ATARI || MAC || HP300 || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || HPDCA=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
---help---
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 31cff1fde9c5..8bf52e30794c 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m)
# override top level makefile
AS += -m68020
LDFLAGS := -m m68kelf
+LDFLAGS_BLOB := --format binary --oformat elf32-m68k
ifneq ($(COMPILE_ARCH),$(ARCH))
# prefix for cross-compiling binaries
CROSS_COMPILE = m68k-linux-
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index bebb2d4b171c..bceff2e4c7c4 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -17,6 +17,7 @@
#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/seq_file.h>
+#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 5abf761945ac..49e2b36659c9 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -21,6 +21,7 @@
#include <linux/rtc.h>
#include <linux/init.h>
#include <linux/vt_kern.h>
+#include <linux/interrupt.h>
#ifdef CONFIG_ZORRO
#include <linux/zorro.h>
#endif
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index 54f4d43d1ed3..5dae74f908f3 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -6,6 +6,7 @@
#include <linux/console.h>
#include <linux/rtc.h>
#include <linux/vt_kern.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/bootinfo.h>
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 8fc840c0bafc..80c45418188c 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -168,7 +168,7 @@ asmlinkage void IRQ_NAME(n); \
void atari_slow_irq_##n##_dummy (void) { \
__asm__ (__ALIGN_STR "\n" \
"atari_slow_irq_" #n "_handler:\t" \
-" addql #1,%5\n" /* local_irq_count++ */ \
+" addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \
SAVE_ALL_INT "\n" \
GET_CURRENT(%%d0) "\n" \
" andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \
@@ -194,7 +194,7 @@ __asm__ (__ALIGN_STR "\n" \
"n" (PT_OFF_SR), "n" (n), \
"i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \
: (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \
- "m" (local_irq_count(0)) \
+ "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \
); \
for (;;); /* fake noreturn */ \
}
@@ -276,7 +276,7 @@ __asm__ (__ALIGN_STR "\n"
"atari_fast_irq_handler:
orw #0x700,%%sr /* disable all interrupts */
atari_prio_irq_handler:\t
- addql #1,%2\n" /* local_irq_count++ */
+ addl %3,%2\n" /* preempt_count() += HARDIRQ_OFFSET */
SAVE_ALL_INT "\n"
GET_CURRENT(%%d0) "
/* get vector number from stack frame and convert to source */
@@ -297,7 +297,7 @@ atari_prio_irq_handler:\t
addql #4,%%sp
jbra ret_from_interrupt"
: : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC),
- "m" (local_irq_count(0))
+ "m" (preempt_count()), "di" (HARDIRQ_OFFSET)
);
for (;;);
}
@@ -481,8 +481,7 @@ int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
irq_node_t *node;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (irq_handler[irq].handler != atari_call_irq_list) {
/* Only one handler yet, make a node for this first one */
@@ -507,7 +506,7 @@ int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
node->next = irq_handler[irq].dev_id;
irq_handler[irq].dev_id = node;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
} else {
printk ("%s: Irq %d allocated by other type int (call from %s)\n",
@@ -531,13 +530,12 @@ void atari_free_irq(unsigned int irq, void *dev_id)
if (vectors[vector] == bad_interrupt)
goto not_found;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (irq_handler[irq].handler != atari_call_irq_list) {
/* It's the only handler for the interrupt */
if (irq_handler[irq].dev_id != dev_id) {
- restore_flags(flags);
+ local_irq_restore(flags);
goto not_found;
}
irq_handler[irq].handler = NULL;
@@ -548,7 +546,7 @@ void atari_free_irq(unsigned int irq, void *dev_id)
atari_disable_irq(irq);
atari_turnoff_irq(irq);
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -557,7 +555,7 @@ void atari_free_irq(unsigned int irq, void *dev_id)
if ((*list)->dev_id == dev_id) break;
}
if (!*list) {
- restore_flags(flags);
+ local_irq_restore(flags);
goto not_found;
}
@@ -574,7 +572,7 @@ void atari_free_irq(unsigned int irq, void *dev_id)
node->handler = NULL; /* Mark it as free for reallocation */
}
- restore_flags(flags);
+ local_irq_restore(flags);
return;
not_found:
diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c
index 7b401d17fef9..d3a60be60069 100644
--- a/arch/m68k/atari/atasound.c
+++ b/arch/m68k/atari/atasound.c
@@ -58,8 +58,7 @@ void atari_mksound (unsigned int hz, unsigned int ticks)
unsigned char tmp;
int period;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Disable generator A in mixer control. */
@@ -106,5 +105,5 @@ void atari_mksound (unsigned int hz, unsigned int ticks)
tmp &= ~1;
sound_ym.wd_data = tmp;
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 035bb3e264dc..8fa786dbd982 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -509,12 +509,11 @@ static void atari_heartbeat( int on )
if (atari_dont_touch_floppy_select)
return;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
tmp = sound_ym.rd_data_reg_sel;
sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
- restore_flags(flags);
+ local_irq_restore(flags);
}
#endif
@@ -569,7 +568,7 @@ static void atari_reset (void)
/* processor independent: turn off interrupts and reset the VBR;
* the caches must be left enabled, else prefetching the final jump
* instruction doesn't work. */
- cli();
+ local_irq_disable();
__asm__ __volatile__
("moveq #0,%/d0\n\t"
"movec %/d0,%/vbr"
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index 1aff226be34b..ec7230628c76 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -33,6 +33,7 @@
#include <linux/genhd.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/atari_stdma.h>
#include <asm/atariints.h>
@@ -75,10 +76,9 @@ static void stdma_int (int irq, void *dummy, struct pt_regs *fp);
void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
{
- unsigned long oldflags;
+ unsigned long flags;
- save_flags(oldflags);
- cli(); /* protect lock */
+ local_irq_save(flags); /* protect lock */
while(stdma_locked)
/* Since the DMA is used for file system purposes, we
@@ -89,7 +89,7 @@ void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
stdma_locked = 1;
stdma_isr = handler;
stdma_isr_data = data;
- restore_flags(oldflags);
+ local_irq_restore(flags);
}
@@ -106,17 +106,16 @@ void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
void stdma_release(void)
{
- unsigned long oldflags;
+ unsigned long flags;
+
+ local_irq_save(flags);
- save_flags(oldflags);
- cli();
-
stdma_locked = 0;
stdma_isr = NULL;
stdma_isr_data = NULL;
wake_up(&stdma_wait);
- restore_flags(oldflags);
+ local_irq_restore(flags);
}
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 1c9268b5ed4f..cc1586d87845 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -765,7 +765,7 @@ static int unswap_by_read(unsigned short *map, unsigned long max,
return -ENOMEM;
}
read_lock(&tasklist_lock);
- for_each_task(p)
+ for_each_process(p)
unswap_process(p->mm, entry, page);
read_unlock(&tasklist_lock);
shmem_unuse(entry, page);
@@ -984,7 +984,7 @@ static void do_stram_request(request_queue_t *q)
unsigned long len = req->current_nr_sectors << 9;
if ((start + len) > swap_end) {
printk( KERN_ERR "stram: bad access beyond end of device: "
- "block=%ld, count=%ld\n",
+ "block=%ld, count=%d\n",
req->sector,
req->current_nr_sectors );
end_request(req, 0);
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index b57a80594a9a..98e344a0111c 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -216,8 +216,7 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
schedule_timeout(HWCLK_POLL_INTERVAL);
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
if (!op) {
sec = RTC_READ( RTC_SECONDS );
@@ -238,7 +237,7 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
}
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
- restore_flags(flags);
+ local_irq_restore(flags);
if (!op) {
/* read: adjust values */
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index eff77830e92c..58771d3367be 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -24,6 +24,7 @@
#include <linux/major.h>
#include <linux/genhd.h>
#include <linux/rtc.h>
+#include <linux/interrupt.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -358,8 +359,7 @@ int bvme6000_set_clock_mmss (unsigned long nowtime)
? real_minutes - rtc_minutes
: rtc_minutes - real_minutes) < 30)
{
- save_flags(flags);
- cli();
+ local_irq_save(flags);
rtc_tenms = rtc->bcd_tenms;
while (rtc_tenms == rtc->bcd_tenms)
;
@@ -367,7 +367,7 @@ int bvme6000_set_clock_mmss (unsigned long nowtime)
;
rtc->bcd_min = bin2bcd(real_minutes);
rtc->bcd_sec = bin2bcd(real_seconds);
- restore_flags(flags);
+ local_irq_restore(flags);
}
else
retval = -1;
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index 071771d0182b..e9fe8968fb5f 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -49,8 +49,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch (cmd) {
case RTC_RD_TIME: /* Read the time/date from RTC */
{
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Ensure clock and real-time-mode-register are accessible */
msr = rtc->msr & 0xc0;
rtc->msr = 0x40;
@@ -66,7 +65,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
} while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
rtc->msr = msr;
- restore_flags(flags);
+ local_irq_restore(flags);
return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
-EFAULT : 0;
}
@@ -106,8 +105,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (yrs >= 2070)
return -EINVAL;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Ensure clock and real-time-mode-register are accessible */
msr = rtc->msr & 0xc0;
rtc->msr = 0x40;
@@ -125,7 +123,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
rtc->t0cr_rtmr = yrs%4 | 0x08;
rtc->msr = msr;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
default:
@@ -179,7 +177,6 @@ int __init rtc_DP8570A_init(void)
return -ENODEV;
printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
- misc_register(&rtc_dev);
- return 0;
+ return misc_register(&rtc_dev);
}
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 6e371c61c727..1faabadaf569 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -552,10 +552,10 @@ sys_call_table:
.long sys_adjtimex
.long sys_mprotect /* 125 */
.long sys_sigprocmask
- .long sys_create_module
+ .long sys_ni_syscall /* old "create_module" */
.long sys_init_module
.long sys_delete_module
- .long sys_get_kernel_syms /* 130 */
+ .long sys_ni_syscall /* 130 - old "get_kernel_syms" */
.long sys_quotactl
.long sys_getpgid
.long sys_fchdir
@@ -592,7 +592,7 @@ sys_call_table:
.long sys_setresuid16
.long sys_getresuid16 /* 165 */
.long sys_getpagesize
- .long sys_query_module
+ .long sys_ni_syscall /* old sys_query_module */
.long sys_poll
.long sys_nfsservctl
.long sys_setresgid16 /* 170 */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index bcaba1d0d973..bccb3147ee81 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -21,7 +21,7 @@
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
** 98/04/25 Phil Blundell: added HP300 support
-** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
+** 1998/08/30 David Kilzer: Added support for font_desc structures
** for linux-2.1.115
** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01)
**
@@ -130,7 +130,7 @@
*
* mmu_engage
* ----------
- * Thanks to a small helping routine enabling the mmu got quiet simple
+ * Thanks to a small helping routine enabling the mmu got quite simple
* and there is only one way left. mmu_engage makes a complete a new mapping
* that only includes the absolute necessary to be able to jump to the final
* postion and to restore the original mapping.
@@ -238,7 +238,7 @@
* In theory these could be determined at run time or handed
* over by the booter. But, let's be real, it's a fine hard
* coded value. (But, you will notice the code is run-time
- * flexible!) A pointer to the font's struct fbcon_font_desc
+ * flexible!) A pointer to the font's struct font_desc
* is kept locally in Lconsole_font. It is used to determine
* font size information dynamically.
*
@@ -1202,7 +1202,7 @@ L(not6000):
*
* Map the kernel (that's already done),
* Map the I/O (on most machines that's the
- * 0x5000.0000 ... 0x5200.0000 range,
+ * 0x5000.0000 ... 0x5300.0000 range,
* Map the video frame buffer using as few pages
* as absolutely (this requirement mostly stems from
* the fact that when the frame buffer is at
@@ -1246,10 +1246,11 @@ L(mmu_init_mac):
andl L(mac_videobase),%d0
mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
- mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */
- mmu_map_eq #0x50000000,#0x02000000,%d3
- mmu_map_eq #0x60000000,#0x00400000,%d3
- mmu_map_eq #0x9c000000,#0x00400000,%d3
+ /* The ROM starts at 4000 0000 */
+ mmu_map_eq #0x40000000,#0x02000000,%d3
+ /* IO devices */
+ mmu_map_eq #0x50000000,#0x03000000,%d3
+ /* NuBus slot space */
mmu_map_tt #1,#0xf8000000,#0x08000000,%d3
jbra L(mmu_init_done)
@@ -1461,6 +1462,9 @@ L(mmu_fixup_done):
andl L(mac_videobase),%d0
addl #VIDEOMEMBASE,%d0
movel %d0,L(mac_videobase)
+#ifdef MAC_SERIAL_DEBUG
+ orl #0x50000000,L(mac_sccbase)
+#endif
1:
#endif
@@ -3032,10 +3036,6 @@ func_start serial_putc,%d0/%d1/%a0/%a1
#ifdef CONFIG_MAC
is_not_mac(5f)
-#ifdef CONSOLE
- console_putc %d0
-#endif /* CONSOLE */
-
#ifdef MAC_SERIAL_DEBUG
#ifdef MAC_USE_SCC_A
@@ -3371,7 +3371,7 @@ console_clear_loop:
* a1 = address of Lconsole_font pointer
*/
lea %pc@(L(console_font)),%a1
- movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */
+ movel %a0,%a1@ /* store pointer to struct font_desc in Lconsole_font */
tstl %a0
jeq 1f
@@ -3383,10 +3383,10 @@ console_clear_loop:
*/
/* ASSERT: a0 = contents of Lconsole_font */
movel %d3,%d0 /* screen width in pixels */
- divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */
+ divul %a0@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */
movel %d4,%d1 /* screen height in pixels */
- divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */
+ divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */
movel %d0,%a2@(Lconsole_struct_num_columns)
movel %d1,%a2@(Lconsole_struct_num_rows)
@@ -3430,6 +3430,10 @@ L(console_put_stats):
putn %pc@(L(cputype))
putc '\n'
+#ifdef MAC_SERIAL_DEBUG
+ putn %pc@(L(mac_sccbase))
+ putc '\n'
+#endif
# if defined(MMU_PRINT)
jbsr mmu_print_machine_cpu_types
# endif /* MMU_PRINT */
@@ -3489,7 +3493,7 @@ console_scroll:
movel %pc@(L(console_font)),%a0
tstl %a0
jeq 1f
- mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */
+ mulul %a0@(FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */
addal %d5,%a2
/*
@@ -3508,7 +3512,7 @@ console_scroll:
lea %pc@(L(mac_rowbytes)),%a0
movel %a0@,%d6
movel %pc@(L(console_font)),%a0
- subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */
+ subl %a0@(FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */
mulul %d4,%d6 /* scan line bytes x num scan lines */
divul #32,%d6 /* we'll move 8 longs at a time */
subq #1,%d6
@@ -3527,7 +3531,7 @@ console_scroll_loop:
lea %pc@(L(mac_rowbytes)),%a0
movel %a0@,%d6
movel %pc@(L(console_font)),%a0
- mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */
+ mulul %a0@(FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */
divul #32,%d6 /* we'll move 8 words at a time */
subq #1,%d6
@@ -3606,19 +3610,19 @@ console_not_home:
movel %a0@(Lconsole_struct_num_columns),%d1
cmpl %d1,%d0
jcs 1f
- putc '\n' /* recursion is OK! */
+ console_putc #'\n' /* recursion is OK! */
1:
movel %a0@(Lconsole_struct_cur_row),%d1
/*
* At this point we make a shift in register usage
- * a0 = address of pointer to font data (fbcon_font_desc)
+ * a0 = address of pointer to font data (font_desc)
*/
movel %pc@(L(console_font)),%a0
- movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */
+ movel %a0@(FONT_DESC_DATA),%a1 /* Load font_desc.data into a1 */
andl #0x000000ff,%d7
/* ASSERT: a0 = contents of Lconsole_font */
- mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */
+ mulul %a0@(FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */
addl %d7,%a1 /* a1 = points to char image */
/*
@@ -3631,15 +3635,15 @@ console_not_home:
* d7 = count down for the font's pixel count in height
*/
/* ASSERT: a0 = contents of Lconsole_font */
- mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0
- mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1
- movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */
+ mulul %a0@(FONT_DESC_WIDTH),%d0
+ mulul %a0@(FONT_DESC_HEIGHT),%d1
+ movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load font_desc.height into d7 */
subq #1,%d7
console_read_char_scanline:
moveb %a1@+,%d3
/* ASSERT: a0 = contents of Lconsole_font */
- movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */
+ movel %a0@(FONT_DESC_WIDTH),%d6 /* Load font_desc.width into d6 */
subql #1,%d6
console_do_font_scanline:
@@ -3650,7 +3654,7 @@ console_do_font_scanline:
dbra %d6,console_do_font_scanline
/* ASSERT: a0 = contents of Lconsole_font */
- subl %a0@(FBCON_FONT_DESC_WIDTH),%d0
+ subl %a0@(FONT_DESC_WIDTH),%d0
addq #1,%d1
dbra %d7,console_read_char_scanline
@@ -3848,7 +3852,7 @@ L(console_globals):
.long 0 /* left edge */
.long 0 /* mac putc */
L(console_font):
- .long 0 /* pointer to console font (struct fbcon_font_desc) */
+ .long 0 /* pointer to console font (struct font_desc) */
#endif /* CONSOLE */
#if defined(MMU_PRINT)
diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c
index 55a386813236..4dd235d15b29 100644
--- a/arch/m68k/kernel/m68k_defs.c
+++ b/arch/m68k/kernel/m68k_defs.c
@@ -78,13 +78,13 @@ int main(void)
DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
DEFINE(BIR_DATA, offsetof(struct bi_record, data));
- /* offsets into fbcon_font_desc (video/font.h) */
- DEFINE(FBCON_FONT_DESC_IDX, offsetof(struct fbcon_font_desc, idx));
- DEFINE(FBCON_FONT_DESC_NAME, offsetof(struct fbcon_font_desc, name));
- DEFINE(FBCON_FONT_DESC_WIDTH, offsetof(struct fbcon_font_desc, width));
- DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height));
- DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data));
- DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref));
+ /* offsets into font_desc (drivers/video/console/font.h) */
+ DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
+ DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
+ DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
+ DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
+ DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
+ DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
/* signal defines */
DEFINE(SIGSEGV, SIGSEGV);
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 15b76c74ba60..ad8aebdfd0e5 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -26,7 +26,6 @@ asmlinkage long long __muldi3 (long long, long long);
extern char m68k_debug_device[];
extern void dump_thread(struct pt_regs *, struct user *);
-extern int dump_fpu(elf_fpregset_t *);
/* platform dependent support */
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 5c50d1f142a2..4d19c1c3979b 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -202,14 +202,15 @@ void flush_thread(void)
asmlinkage int m68k_fork(struct pt_regs *regs)
{
struct task_struct *p;
- p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL);
+ p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
asmlinkage int m68k_vfork(struct pt_regs *regs)
{
struct task_struct *p;
- p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL);
+ p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
+ NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
@@ -218,15 +219,17 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
unsigned long clone_flags;
unsigned long newsp;
struct task_struct *p;
- int *user_tid;
+ int *parent_tidptr, *child_tidptr;
/* syscall2 puts clone_flags in d1 and usp in d2 */
clone_flags = regs->d1;
newsp = regs->d2;
- user_tid = (int *)regs->d3;
+ parent_tidptr = (int *)regs->d3;
+ child_tidptr = (int *)regs->d4;
if (!newsp)
newsp = rdusp();
- p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, user_tid);
+ p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0,
+ parent_tidptr, child_tidptr);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index bf1d0ab11f52..ba0ea7d6361c 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -380,9 +380,6 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_SUN3X
if (MACH_IS_SUN3X) {
dvma_init();
-#ifdef CONFIG_SUN3X_ZS
- sun_serial_setup();
-#endif
}
#endif
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index e45e7441d1a3..908785fd123f 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -1101,7 +1101,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV:
case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
- if (do_coredump(signr, regs))
+ if (do_coredump(signr, exit_code, regs))
exit_code |= 0x80;
/* FALLTHRU */
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 4343116eef4e..ad20bedba50c 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -820,32 +820,43 @@ asmlinkage void buserr_c(struct frame *fp)
static int kstack_depth_to_print = 48;
-extern struct module kernel_module;
+
+extern char _stext, _etext;
+
+#ifdef CONFIG_MODULES
+
+/* FIXME: Accessed without a lock --RR */
+extern struct list_head modules;
static inline int kernel_text_address(unsigned long addr)
{
-#ifdef CONFIG_MODULES
struct module *mod;
-#endif
- extern char _stext, _etext;
if (addr >= (unsigned long) &_stext &&
addr <= (unsigned long) &_etext)
return 1;
-#ifdef CONFIG_MODULES
- for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+ list_for_each_entry(mod, &modules, list) {
/* mod_bound tests for addr being inside the vmalloc'ed
* module area. Of course it'd be better to test only
* for the .text subset... */
- if (mod_bound(addr, 0, mod))
+ if (mod_bound((void *)addr, 0, mod))
return 1;
}
-#endif
return 0;
}
+#else // !CONFIG_MODULES
+
+static inline int kernel_text_address(unsigned long addr)
+{
+ return (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext);
+}
+
+#endif // !CONFIG_MODULES
+
void show_trace(unsigned long *stack)
{
unsigned long *endstack;
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index b30459aedb31..17ce0248fbfe 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -90,7 +90,7 @@ static void mac_get_model(char *str);
void mac_bang(int irq, void *vector, struct pt_regs *p)
{
- printk("Resetting ...\n");
+ printk(KERN_INFO "Resetting ...\n");
mac_reset();
}
@@ -181,17 +181,16 @@ int __init mac_parse_bootinfo(const struct bi_record *record)
static void mac_cache_card_flush(int writeback)
{
- unsigned long cpu_flags;
- save_flags(cpu_flags);
- cli();
+ unsigned long flags;
+ local_irq_save(flags);
via_flush_cache();
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
}
void __init config_mac(void)
{
if (!MACH_IS_MAC) {
- printk("ERROR: no Mac, but config_mac() called!! \n");
+ printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
}
mach_sched_init = mac_sched_init;
@@ -326,13 +325,14 @@ static struct mac_model mac_data_table[]=
*/
{ MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_Q605_ACC, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
/* The Q700 does have a NS Sonic */
- { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS},
+ { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC, MAC_ETHER_MACE, MAC_NUBUS},
{ MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
@@ -345,8 +345,8 @@ static struct mac_model mac_data_table[]=
{ MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/* These have the comm slot, and therefore the possibility of SONIC ethernet */
+ { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
@@ -358,7 +358,7 @@ static struct mac_model mac_data_table[]=
/* The C610 may or may not have SONIC. We probe to make sure */
{ MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS},
+ { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC, MAC_ETHER_MACE, MAC_NUBUS},
/*
* The PowerBooks all the same "Combo" custom IC for SCSI and SCC
@@ -411,7 +411,7 @@ void mac_identify(void)
/* no bootinfo model id -> NetBSD booter was used! */
/* XXX FIXME: breaks for model > 31 */
model=(mac_bi_data.cpuid>>2)&63;
- printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+ printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
}
macintosh_config = mac_data_table;
@@ -429,22 +429,22 @@ void mac_identify(void)
iop_preinit();
mac_debug_init();
- printk ("Detected Macintosh model: %d \n", model);
+ printk (KERN_INFO "Detected Macintosh model: %d \n", model);
/*
* Report booter data:
*/
- printk (" Penguin bootinfo data:\n");
- printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
+ printk (KERN_DEBUG " Penguin bootinfo data:\n");
+ printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
mac_bi_data.videoaddr, mac_bi_data.videorow,
mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
mac_bi_data.dimensions >> 16);
- printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+ printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
mac_bi_data.videological, mac_orig_videoaddr,
mac_bi_data.sccbase);
- printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+ printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
mac_bi_data.boottime, mac_bi_data.gmtbias);
- printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+ printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
#if 0
printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
@@ -467,7 +467,7 @@ void mac_identify(void)
MACHW_SET(MAC_SCSI_96_2);
break;
default:
- printk("config.c: wtf: unknown scsi, using 53c80\n");
+ printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
MACHW_SET(MAC_SCSI_80);
break;
@@ -481,7 +481,7 @@ void mac_identify(void)
void mac_report_hardware(void)
{
- printk("Apple Macintosh %s\n", macintosh_config->name);
+ printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
}
static void mac_get_model(char *str)
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index 627a7580fa01..737037841835 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -111,6 +111,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
@@ -212,20 +213,19 @@ static int iop_alive(volatile struct mac_iop *iop)
static struct iop_msg *iop_alloc_msg(void)
{
int i;
- ulong cpu_flags;
+ unsigned long flags;
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) {
iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING;
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
return &iop_msg_pool[i];
}
}
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
return NULL;
}
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 4ef9220463e2..b9f73f9e76d0 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -187,8 +187,7 @@ void mac_mksound( unsigned int freq, unsigned int length )
return;
}
- save_flags( flags );
- cli();
+ local_irq_save(flags);
del_timer( &mac_sound_timer );
@@ -210,7 +209,7 @@ void mac_mksound( unsigned int freq, unsigned int length )
mac_sound_timer.expires = jiffies + length;
add_timer( &mac_sound_timer );
- restore_flags( flags );
+ local_irq_restore(flags);
}
/*
@@ -240,8 +239,7 @@ static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsig
mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
/* this is reasonably big for small frequencies */
- save_flags( flags );
- cli();
+ local_irq_save(flags);
/* set the volume */
mac_asc_regs[ 0x806 ] = volume;
@@ -263,7 +261,7 @@ static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsig
mac_sound_timer.expires = jiffies + 1;
add_timer( &mac_sound_timer );
- restore_flags( flags );
+ local_irq_restore(flags);
}
/*
@@ -283,8 +281,7 @@ static void mac_quadra_ring_bell( unsigned long ignored )
* ...and the possibility to use a real sample (a boingy noise, maybe...)
*/
- save_flags( flags );
- cli();
+ local_irq_save(flags);
del_timer( &mac_sound_timer );
@@ -301,7 +298,7 @@ static void mac_quadra_ring_bell( unsigned long ignored )
else
mac_asc_regs[ 0x801 ] = 0;
- restore_flags( flags );
+ local_irq_restore(flags);
}
/*
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 40938c05f60c..4f8ea17f57ac 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -276,15 +276,14 @@ void mac_init_IRQ(void)
static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
{
- unsigned long cpu_flags;
+ unsigned long flags;
irq_node_t *cur;
if (!node->dev_id)
printk("%s: Warning: dev_id of %s is zero\n",
__FUNCTION__, node->devname);
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
cur = *list;
@@ -309,27 +308,26 @@ static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
node->next = cur;
*list = node;
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
}
static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
{
- unsigned long cpu_flags;
+ unsigned long flags;
irq_node_t *node;
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
for (node = *list; node; list = &node->next, node = *list) {
if (node->dev_id == dev_id) {
*list = node->next;
/* Mark it as free. */
node->handler = NULL;
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
return;
}
}
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
}
@@ -343,7 +341,7 @@ static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
void mac_do_irq_list(int irq, struct pt_regs *fp)
{
irq_node_t *node, *slow_nodes;
- unsigned long cpu_flags;
+ unsigned long flags;
kstat_cpu(0).irqs[irq]++;
@@ -360,8 +358,8 @@ void mac_do_irq_list(int irq, struct pt_regs *fp)
node = node->next)
node->handler(irq, node->dev_id, fp);
if (!node) return;
- save_flags(cpu_flags);
- restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700));
+ local_save_flags(flags);
+ local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700));
/* if slow handlers exists, serve them now */
slow_nodes = node;
for (; node; node = node->next) {
@@ -735,15 +733,15 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
{
volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2;
unsigned char reg;
- unsigned long cpu_flags;
+ unsigned long flags;
/* Read RR3 from the chip. Always do this on channel A */
/* This must be an atomic operation so disable irqs. */
- save_flags(cpu_flags); cli();
+ local_irq_save(flags);
*scc = 3;
reg = *scc;
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
/* Now dispatch. Bits 0-2 are for channel B and */
/* bits 3-5 are for channel A. We can safely */
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 04fc953d271c..61f41a8026a8 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -165,11 +165,10 @@ static void via_pram_writebyte(__u8 data)
static void via_pram_command(int command, __u8 *data)
{
- unsigned long cpu_flags;
+ unsigned long flags;
int is_read;
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
/* Enable the RTC and make sure the strobe line is high */
@@ -193,7 +192,7 @@ static void via_pram_command(int command, __u8 *data)
via1[vBufB] |= VIA1B_vRTCEnb;
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
}
static __u8 via_read_pram(int offset)
@@ -405,7 +404,7 @@ void mac_poweroff(void)
pmu_shutdown();
#endif
}
- sti();
+ local_irq_enable();
printk("It is now safe to turn off your Macintosh.\n");
while(1);
}
@@ -413,7 +412,7 @@ void mac_poweroff(void)
void mac_reset(void)
{
if (macintosh_config->adb_type == MAC_ADB_II) {
- unsigned long cpu_flags;
+ unsigned long flags;
/* need ROMBASE in booter */
/* indeed, plus need to MAP THE ROM !! */
@@ -429,12 +428,11 @@ void mac_reset(void)
* MSch: Machines known to crash on ROM reset ...
*/
} else {
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
rom_reset();
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
}
#ifdef CONFIG_ADB_CUDA
} else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
@@ -459,7 +457,7 @@ void mac_reset(void)
unsigned long virt = (unsigned long) mac_reset;
unsigned long phys = virt_to_phys(mac_reset);
unsigned long offset = phys-virt;
- cli(); /* lets not screw this up, ok? */
+ local_irq_disable(); /* lets not screw this up, ok? */
__asm__ __volatile__(".chip 68030\n\t"
"pmove %0,%/tt0\n\t"
".chip 68k"
@@ -495,7 +493,7 @@ void mac_reset(void)
}
/* should never get here */
- sti();
+ local_irq_enable();
printk ("Restart failed. Please restart manually.\n");
while(1);
}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 4c453339112b..53b448deb37a 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -137,15 +137,15 @@ void __init via_init(void)
panic("UNKNOWN VIA TYPE");
}
- printk("VIA1 at %p is a 6522 or clone\n", via1);
+ printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
- printk("VIA2 at %p is ", via2);
+ printk(KERN_INFO "VIA2 at %p is ", via2);
if (rbv_present) {
- printk("an RBV\n");
+ printk(KERN_INFO "an RBV\n");
} else if (oss_present) {
- printk("an OSS\n");
+ printk(KERN_INFO "an OSS\n");
} else {
- printk("a 6522 or clone\n");
+ printk(KERN_INFO "a 6522 or clone\n");
}
#ifdef DEBUG_VIA
@@ -291,22 +291,22 @@ void __init via_register_interrupts(void)
void via_debug_dump(void)
{
- printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+ printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
- printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
+ printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
if (oss_present) {
- printk("VIA2: <OSS>\n");
+ printk(KERN_DEBUG "VIA2: <OSS>\n");
} else if (rbv_present) {
- printk("VIA2: IFR = 0x%02X IER = 0x%02X\n",
+ printk(KERN_DEBUG "VIA2: IFR = 0x%02X IER = 0x%02X\n",
(uint) via2[rIFR], (uint) via2[rIER]);
- printk(" SIFR = 0x%02X SIER = 0x%02X\n",
+ printk(KERN_DEBUG " SIFR = 0x%02X SIER = 0x%02X\n",
(uint) via2[rSIFR], (uint) via2[rSIER]);
} else {
- printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+ printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
(uint) via2[vDirA], (uint) via2[vDirB],
(uint) via2[vACR]);
- printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
+ printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
(uint) via2[vPCR],
(uint) via2[vIFR], (uint) via2[vIER]);
}
@@ -374,7 +374,10 @@ void __init via_nubus_init(void)
if (!rbv_present) {
/* set the line to be an output on non-RBV machines */
- via2[vDirB] |= 0x02;
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ via2[vDirB] |= 0x02;
+ }
}
/* this seems to be an ADB bit on PMU machines */
@@ -390,8 +393,23 @@ void __init via_nubus_init(void)
via2[rSIER] = 0x7F;
via2[rSIER] = nubus_active | 0x80;
} else {
- via2[vBufA] = 0xFF;
- via2[vDirA] = ~nubus_active;
+ /* These are ADB bits on PMU */
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ switch(macintosh_config->ident)
+ {
+ case MAC_MODEL_II:
+ case MAC_MODEL_IIX:
+ case MAC_MODEL_IICX:
+ case MAC_MODEL_SE30:
+ via2[vBufA] |= 0x3F;
+ via2[vDirA] = ~nubus_active | 0xc0;
+ break;
+ default:
+ via2[vBufA] = 0xFF;
+ via2[vDirA] = ~nubus_active;
+ }
+ }
}
}
@@ -481,7 +499,7 @@ void via_irq_enable(int irq) {
int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE
- printk("via_irq_enable(%d)\n", irq);
+ printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
#endif
if (irq_src == 1) {
@@ -508,7 +526,21 @@ void via_irq_enable(int irq) {
via2[rSIER] = IER_SET_BIT(irq_idx);
} else {
/* Make sure the bit is an input, to enable the irq */
- via2[vDirA] &= ~irq_bit;
+ /* But not on PowerBooks, that's ADB... */
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ switch(macintosh_config->ident)
+ {
+ case MAC_MODEL_II:
+ case MAC_MODEL_IIX:
+ case MAC_MODEL_IICX:
+ case MAC_MODEL_SE30:
+ via2[vDirA] &= (~irq_bit | 0xc0);
+ break;
+ default:
+ via2[vDirA] &= ~irq_bit;
+ }
+ }
}
nubus_active |= irq_bit;
}
@@ -520,7 +552,7 @@ void via_irq_disable(int irq) {
int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE
- printk("via_irq_disable(%d)\n", irq);
+ printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
#endif
if (irq_src == 1) {
@@ -533,7 +565,11 @@ void via_irq_disable(int irq) {
via2[rSIER] = IER_CLR_BIT(irq_idx);
} else {
/* disable the nubus irq by changing dir to output */
- via2[vDirA] |= irq_bit;
+ /* except on PMU */
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ via2[vDirA] |= irq_bit;
+ }
}
nubus_active &= ~irq_bit;
}
diff --git a/arch/m68k/mm/extable.c b/arch/m68k/mm/extable.c
index 1f8d9e8c3323..bb854b6e92e9 100644
--- a/arch/m68k/mm/extable.c
+++ b/arch/m68k/mm/extable.c
@@ -33,23 +33,29 @@ search_one_table(const struct exception_table_entry *first,
unsigned long
search_exception_table(unsigned long addr)
{
- unsigned long ret;
+ unsigned long ret = 0;
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
- if (ret) return ret;
+ return ret;
#else
+ unsigned long flags;
+ struct list_head *i;
+
/* The kernel is the last "module" -- no need to treat it special. */
- struct module *mp;
- for (mp = module_list; mp != NULL; mp = mp->next) {
- if (mp->ex_table_start == NULL)
+ spin_lock_irqsave(&modlist_lock, flags);
+ list_for_each(i, &extables) {
+ struct exception_table *ex
+ = list_entry(i, struct exception_table, list);
+ if (ex->num_entries == 0)
continue;
- ret = search_one_table(mp->ex_table_start,
- mp->ex_table_end-1, addr);
- if (ret) return ret;
+ ret = search_one_table(ex->entry,
+ ex->entry + ex->num_entries - 1, addr);
+ if (ret)
+ break;
}
+ spin_unlock_irqrestore(&modlist_lock, flags);
+ return ret;
#endif
-
- return 0;
}
diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c
index dd3411170472..a1dcc2ed06aa 100644
--- a/arch/m68k/mm/sun3mmu.c
+++ b/arch/m68k/mm/sun3mmu.c
@@ -83,7 +83,7 @@ void __init paging_init(void)
/* now change pg_table to kernel virtual addresses */
pg_table = (pte_t *) __va ((unsigned long) pg_table);
for (i=0; i<PTRS_PER_PTE; ++i, ++pg_table) {
- pte_t pte = __mk_pte(address, PAGE_INIT);
+ pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT);
if (address >= (unsigned long)high_memory)
pte_val (pte) = 0;
set_pte (pg_table, pte);
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 25c324c036f4..5f5342a2a67f 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -23,6 +23,7 @@
#include <linux/major.h>
#include <linux/genhd.h>
#include <linux/rtc.h>
+#include <linux/interrupt.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -209,10 +210,9 @@ static void scc_write (char ch)
void m147_scc_write (struct console *co, const char *str, unsigned count)
{
- unsigned long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
while (count--)
{
@@ -220,7 +220,7 @@ void m147_scc_write (struct console *co, const char *str, unsigned count)
scc_write ('\r');
scc_write (*str++);
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
void mvme147_init_console_port (struct console *co, int cflag)
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index cf42754a0980..713c18b54c7e 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -24,6 +24,7 @@
#include <linux/major.h>
#include <linux/genhd.h>
#include <linux/rtc.h>
+#include <linux/interrupt.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 6f88e9d2bbd7..ec79bfc53d34 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -48,8 +48,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch (cmd) {
case RTC_RD_TIME: /* Read the time/date from RTC */
{
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Ensure clock and real-time-mode-register are accessible */
rtc->ctrl = RTC_READ;
wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
@@ -62,7 +61,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
wtime.tm_year += 100;
wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
rtc->ctrl = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
-EFAULT : 0;
}
@@ -102,8 +101,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (yrs >= 2070)
return -EINVAL;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
rtc->ctrl = RTC_WRITE;
rtc->bcd_sec = BIN2BCD(sec);
@@ -114,7 +112,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
rtc->bcd_year = BIN2BCD(yrs%100);
rtc->ctrl = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
default:
@@ -168,7 +166,6 @@ int __init rtc_MK48T08_init(void)
return -ENODEV;
printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
- misc_register(&rtc_dev);
- return 0;
+ return misc_register(&rtc_dev);
}
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 54fe9303cbd4..da640dfb0bbd 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
+#include <linux/interrupt.h>
#include <asm/rtc.h>
#include <asm/ptrace.h>
@@ -374,7 +375,7 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
}
if ( irq_tab[irq].state & IRQ_INPROGRESS )
{
- /* some handlers do sti() for irq latency reasons, */
+ /* some handlers do local_irq_enable() for irq latency reasons, */
/* however reentering an active irq handler is not permitted */
#ifdef IP_USE_DISABLE
/* in theory this is the better way to do it because it still */
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index 3aaa166f5612..2c21cfb5337f 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -42,7 +42,6 @@ extern void sun3_get_model (char* model);
extern void idprom_init (void);
extern int sun3_hwclk(int set, struct rtc_time *t);
-extern void sun_serial_setup(void);
volatile char* clock_va;
extern volatile unsigned char* sun3_intreg;
extern unsigned long availmem;
@@ -173,10 +172,6 @@ void __init config_sun3(void)
m68k_memory[0].size=*(romvec->pv_sun3mem);
sun3_bootmem_alloc(memory_start, memory_end);
-
-#ifdef CONFIG_SUN3X_ZS
- sun_serial_setup();
-#endif
}
void __init sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
diff --git a/arch/m68k/sun3/dvma.c b/arch/m68k/sun3/dvma.c
index 1c47cc14415c..af1b60199455 100644
--- a/arch/m68k/sun3/dvma.c
+++ b/arch/m68k/sun3/dvma.c
@@ -1,5 +1,11 @@
-
-/* dvma support routines */
+/*
+ * linux/arch/m68k/sun3/dvma.c
+ *
+ * Written by Sam Creasey
+ *
+ * Sun3 IOMMU routines used for dvma accesses.
+ *
+ */
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -22,7 +28,7 @@ inline unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr)
j = *(volatile unsigned long *)kaddr;
*(volatile unsigned long *)kaddr = j;
- ptep = __mk_pte(kaddr, PAGE_KERNEL);
+ ptep = pfn_pte(virt_to_pfn(kaddr), PAGE_KERNEL);
pte = pte_val(ptep);
// printk("dvma_remap: addr %lx -> %lx pte %08lx len %x\n",
// kaddr, vaddr, pte, len);
diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
index 1015f247ae7e..fce7e6f03172 100644
--- a/arch/m68k/sun3/intersil.c
+++ b/arch/m68k/sun3/intersil.c
@@ -40,7 +40,7 @@ int sun3_hwclk(int set, struct rtc_time *t)
todintersil = (struct intersil_dt *) &intersil_clock->counter;
- save_and_cli(flags);
+ local_irq_save(flags);
intersil_clock->cmd_reg = STOP_VAL;
@@ -68,7 +68,7 @@ int sun3_hwclk(int set, struct rtc_time *t)
intersil_clock->cmd_reg = START_VAL;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
diff --git a/arch/m68k/sun3/prom/console.c b/arch/m68k/sun3/prom/console.c
index 5ec12de10fbd..52c1427863de 100644
--- a/arch/m68k/sun3/prom/console.c
+++ b/arch/m68k/sun3/prom/console.c
@@ -22,9 +22,9 @@ prom_nbgetchar(void)
int i = -1;
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
i = (*(romvec->pv_nbgetchar))();
- restore_flags(flags);
+ local_irq_restore(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
}
@@ -37,9 +37,9 @@ prom_nbputchar(char c)
unsigned long flags;
int i = -1;
- save_flags(flags); cli();
+ local_irq_save(flags);
i = (*(romvec->pv_nbputchar))(c);
- restore_flags(flags);
+ local_irq_restore(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
}
@@ -83,12 +83,12 @@ prom_query_input_device()
};
case PROM_V3:
case PROM_P1275:
- save_flags(flags); cli();
+ local_irq_save(flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
"r" (&current_set[smp_processor_id()]) :
"memory");
- restore_flags(flags);
+ local_irq_restore(flags);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
@@ -133,12 +133,12 @@ prom_query_output_device()
case PROM_V2:
case PROM_V3:
case PROM_P1275:
- save_flags(flags); cli();
+ local_irq_save(flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
"r" (&current_set[smp_processor_id()]) :
"memory");
- restore_flags(flags);
+ local_irq_restore(flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
diff --git a/arch/m68k/sun3/prom/misc.c b/arch/m68k/sun3/prom/misc.c
index 1d19e8d49b91..b88716f2c68c 100644
--- a/arch/m68k/sun3/prom/misc.c
+++ b/arch/m68k/sun3/prom/misc.c
@@ -19,9 +19,9 @@ void
prom_reboot(char *bcommand)
{
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
(*(romvec->pv_reboot))(bcommand);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Drop into the prom, with the chance to continue with the 'go'
@@ -40,9 +40,9 @@ prom_halt(void)
{
unsigned long flags;
again:
- save_flags(flags); cli();
+ local_irq_save(flags);
(*(romvec->pv_halt))();
- restore_flags(flags);
+ local_irq_restore(flags);
goto again; /* PROM is out to get me -DaveM */
}
diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c
index fe148907acd8..52a39cb28b97 100644
--- a/arch/m68k/sun3/sbus.c
+++ b/arch/m68k/sun3/sbus.c
@@ -12,13 +12,9 @@
#include <linux/types.h>
#include <linux/init.h>
-extern void rs_init(void);
-
-void __init sbus_init(void)
+int __init sbus_init(void)
{
-
- rs_init();
-
+ return 0;
}
void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
@@ -27,3 +23,4 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
return (void *)address;
}
+subsys_initcall(sbus_init);
diff --git a/arch/m68k/sun3x/dvma.c b/arch/m68k/sun3x/dvma.c
index 3f28e3565235..4fc997c9b2ef 100644
--- a/arch/m68k/sun3x/dvma.c
+++ b/arch/m68k/sun3x/dvma.c
@@ -102,7 +102,7 @@ inline int dvma_map_cpu(unsigned long kaddr,
pmd_t *pmd;
unsigned long end2;
- if((pmd = pmd_alloc_kernel(pgd, vaddr)) == NULL) {
+ if((pmd = pmd_alloc(&init_mm, pgd, vaddr)) == NULL) {
ret = -ENOMEM;
goto out;
}
@@ -116,7 +116,7 @@ inline int dvma_map_cpu(unsigned long kaddr,
pte_t *pte;
unsigned long end3;
- if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) {
+ if((pte = pte_alloc_kernel(&init_mm, pmd, vaddr)) == NULL) {
ret = -ENOMEM;
goto out;
}
@@ -131,7 +131,8 @@ inline int dvma_map_cpu(unsigned long kaddr,
printk("mapping %08lx phys to %08lx\n",
__pa(kaddr), vaddr);
#endif
- set_pte(pte, __mk_pte(kaddr, PAGE_KERNEL));
+ set_pte(pte, pfn_pte(virt_to_pfn(kaddr),
+ PAGE_KERNEL));
pte++;
kaddr += PAGE_SIZE;
vaddr += PAGE_SIZE;
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
index d738e0536a34..93dd64576e1a 100644
--- a/arch/m68k/sun3x/prom.c
+++ b/arch/m68k/sun3x/prom.c
@@ -37,9 +37,9 @@ extern e_vector vectors[256]; /* arch/m68k/kernel/traps.c */
void sun3x_halt(void)
{
unsigned long flags;
-
+
/* Disable interrupts while we mess with things */
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Restore prom vbr */
__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
@@ -56,13 +56,13 @@ void sun3x_halt(void)
sun3_enable_irq(5);
__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
- restore_flags(flags);
+ local_irq_restore(flags);
}
void sun3x_reboot(void)
{
/* This never returns, don't bother saving things */
- cli();
+ local_irq_disable();
/* Restore prom vbr */
__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index b72f3c2eb65d..683a34e815d4 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -45,7 +45,7 @@ int sun3x_hwclk(int set, struct rtc_time *t)
(struct mostek_dt *)(SUN3X_EEPROM+M_CONTROL);
unsigned long flags;
- save_and_cli(flags);
+ local_irq_save(flags);
if(set) {
h->csr |= C_WRITE;
@@ -69,7 +69,7 @@ int sun3x_hwclk(int set, struct rtc_time *t)
h->csr &= ~C_READ;
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
diff --git a/arch/m68k/vmlinux-std.lds b/arch/m68k/vmlinux-std.lds
index c0ac0012d92d..c31bc1da259b 100644
--- a/arch/m68k/vmlinux-std.lds
+++ b/arch/m68k/vmlinux-std.lds
@@ -47,6 +47,9 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
+ __start___param = .;
+ __param : { *(__param) }
+ __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
@@ -59,6 +62,10 @@ SECTIONS
}
__initcall_end = .;
. = ALIGN(8192);
+ __initramfs_start = .;
+ .init.ramfs : { *(.init.ramfs) }
+ __initramfs_end = .;
+ . = ALIGN(8192);
__init_end = .;
.data.init_task : { *(.data.init_task) } /* The initial task and kernel stack */
diff --git a/arch/m68k/vmlinux-sun3.lds b/arch/m68k/vmlinux-sun3.lds
index 83aa0185079c..9ce55a8120c0 100644
--- a/arch/m68k/vmlinux-sun3.lds
+++ b/arch/m68k/vmlinux-sun3.lds
@@ -43,6 +43,9 @@ __init_begin = .;
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
+ __start___param = .;
+ __param : { *(__param) }
+ __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
@@ -55,6 +58,10 @@ __init_begin = .;
}
__initcall_end = .;
. = ALIGN(8192);
+ __initramfs_start = .;
+ .init.ramfs : { *(.init.ramfs) }
+ __initramfs_end = .;
+ . = ALIGN(8192);
__init_end = .;
.init.task : { *(init_task) }
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index f7e8005ebf38..cb59d60d0fff 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -30,6 +30,13 @@ config RWSEM_GENERIC_SPINLOCK
bool
default y
+config MODE_TT
+ bool
+ default y
+
+config MODE_SKAS
+ bool
+ default y
menu "Code maturity level options"
@@ -64,9 +71,41 @@ config BINFMT_MISC
config HOSTFS
tristate "Host filesystem"
+ help
+ While the User-Mode Linux port uses its own root file system for
+ booting and normal file access, this module lets the UML user
+ access files stored on the host. It does not require any
+ network connection between the Host and UML. An example use of
+ this might be:
+
+ mount none /tmp/fromhost -t hostfs -o /tmp/umlshare
+
+ where /tmp/fromhost is an empty directory inside UML and
+ /tmp/umlshare is a directory on the host with files the UML user
+ wishes to access.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/hostfs.html>.
+
+ If you'd like to be able to work with files stored on the host,
+ say Y or M here; otherwise say N.
+
config MCONSOLE
bool "Management console"
+ help
+ The user mode linux management console is a low-level interface to
+ the kernel, somewhat like the i386 SysRq interface. Since there is
+ a full-blown operating system running under every user mode linux
+ instance, there is much greater flexibility possible than with the
+ SysRq mechanism.
+
+ If you answer 'Y' to this option, to use this feature, you need the
+ mconsole client (called uml_mconsole) which is present in CVS in
+ 2.4.5-9um and later (path /tools/mconsole), and is also in the
+ distribution RPM package in 2.4.6 and later.
+
+ It is safe to say 'Y' here.
config MAGIC_SYSRQ
bool "Magic SysRq key"
@@ -77,6 +116,16 @@ config HOST_2G_2G
config UML_SMP
bool "Symmetric multi-processing support"
+ help
+ This option enables UML SMP support. UML implements virtual SMP by
+ allowing as many processes to run simultaneously on the host as
+ there are virtual processors configured. Obviously, if the host is
+ a uniprocessor, those processes will timeshare, but, inside UML,
+ will appear to be running simultaneously. If the host is a
+ multiprocessor, then UML processes may run simultaneously, depending
+ on the host scheduler.
+ CONFIG_SMP will be set to whatever this option is set to.
+ It is safe to leave this unchanged.
config SMP
bool
@@ -90,10 +139,27 @@ config NR_CPUS
config NEST_LEVEL
int "Nesting level"
default "0"
+ help
+ This is set to the number of layers of UMLs that this UML will be run
+ in. Normally, this is zero, meaning that it will run directly on the
+ host. Setting it to one will build a UML that can run inside a UML
+ that is running on the host. Generally, if you intend this UML to run
+ inside another UML, set CONFIG_NEST_LEVEL to one more than the host
+ UML.
+
+ Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to
+ greater than one, then the guest UML should have its CONFIG_NEST_LEVEL
+ set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS.
+ Only change this if you are running nested UMLs.
config KERNEL_HALF_GIGS
int "Kernel address space size (in .5G units)"
default "1"
+ help
+ This determines the amount of address space that UML will allocate for
+ its own, measured in half Gigabyte units. The default is 1.
+ Change this only if you need to boot UML with an unusually large amount
+ of physical memory.
config HIGHMEM
bool "Highmem support"
@@ -128,6 +194,7 @@ source "net/Kconfig"
source "fs/Kconfig"
+source "lib/Kconfig"
menu "SCSI support"
@@ -156,6 +223,14 @@ config DEBUG_SLAB
config DEBUGSYM
bool "Enable kernel debugging symbols"
+ help
+ When this is enabled, the User-Mode Linux binary will include
+ debugging symbols. This enlarges the binary by a few megabytes,
+ but aids in tracking down kernel problems in UML. It is required
+ if you intend to do any kernel development.
+
+ If you're truly short on disk space or don't expect to report any
+ bugs back to the UML developers, say N, otherwise say Y.
config PT_PROXY
bool "Enable ptrace proxy"
@@ -164,10 +239,28 @@ config PT_PROXY
config GPROF
bool "Enable gprof support"
depends on DEBUGSYM
+ help
+ This allows profiling of a User-Mode Linux kernel with the gprof
+ utility.
+
+ See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+ details.
+
+ If you're involved in UML kernel development and want to use gprof,
+ say Y. If you're unsure, say N.
config GCOV
bool "Enable gcov support"
depends on DEBUGSYM
+ help
+ This option allows developers to retrieve coverage data from a UML
+ session.
+
+ See <http://user-mode-linux.sourceforge.net/gcov.html> for more
+ details.
+
+ If you're involved in UML kernel development and want to use gcov,
+ say Y. If you're unsure, say N.
endmenu
diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block
index 542627172e92..fba53d9bb983 100644
--- a/arch/um/Kconfig_block
+++ b/arch/um/Kconfig_block
@@ -3,10 +3,31 @@ menu "Block Devices"
config BLK_DEV_UBD
bool "Virtual block device"
+ help
+ The User-Mode Linux port includes a driver called UBD which will let
+ you access arbitrary files on the host computer as block devices.
+ Unless you know that you do not need such virtual block devices say
+ Y here.
config BLK_DEV_UBD_SYNC
bool "Always do synchronous disk IO for UBD"
depends on BLK_DEV_UBD
+ help
+ Writes to the virtual block device are not immediately written to the
+ host's disk; this may cause problems if, for example, the
+ User-Mode Linux 'Virtual Machine' uses a journalling filesystem and
+ the host computer crashes.
+
+ Synchronous operation (i.e. always writing data to the host's disk
+ immediately) is configurable on a per-UBD basis by using a special
+ kernel command line option. Alternatively, you can say Y here to
+ turn on synchronous operation by default for all block devices.
+
+ If you're running a journalling file system (like reiserfs, for
+ example) in your virtual machine, you will want to say Y here. If
+ you care for the safety of the data in your virtual machine, Y is a
+ wise choice too. In all other cases (for example, if you're just
+ playing around with User-Mode Linux) you can choose N.
config BLK_DEV_LOOP
tristate "Loopback device support"
@@ -29,6 +50,19 @@ config BLK_DEV_INITRD
config MMAPPER
tristate "Example IO memory driver"
+ help
+ The User-Mode Linux port can provide support for IO Memory
+ emulation with this option. This allows a host file to be
+ specified as an I/O region on the kernel command line. That file
+ will be mapped into UML's kernel address space where a driver can
+ locate it and do whatever it wants with the memory, including
+ providing an interface to it for UML processes to use.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/iomem.html>.
+
+ If you'd like to be able to provide a simulated IO port space for
+ User-Mode Linux processes, say Y. If unsure, say N.
endmenu
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char
index 8a3367c10310..a21cbbc7efde 100644
--- a/arch/um/Kconfig_char
+++ b/arch/um/Kconfig_char
@@ -7,36 +7,104 @@ config STDIO_CONSOLE
config SSL
bool "Virtual serial line"
+ help
+ The User-Mode Linux environment allows you to create virtual serial
+ lines on the UML that are usually made to show up on the host as
+ ttys or ptys.
+
+ See <http://user-mode-linux.sourceforge.net/input.html> for more
+ information and command line examples of how to use this facility.
+
+ Unless you have a specific reason for disabling this, say Y.
config FD_CHAN
bool "file descriptor channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to already set up file descriptors. Generally, the main
+ console is attached to file descriptors 0 and 1 (stdin and stdout),
+ so it would be wise to leave this enabled unless you intend to
+ attach it to some other host device.
config NULL_CHAN
bool "null channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to a device similar to /dev/null. Data written to it disappears
+ and there is never any data to be read.
config PORT_CHAN
bool "port channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to host portals. They may be accessed with 'telnet <host>
+ <port number>'. Any number of consoles and serial lines may be
+ attached to a single portal, although what UML device you get when
+ you telnet to that portal will be unpredictable.
+ It is safe to say 'Y' here.
config PTY_CHAN
bool "pty channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to host pseudo-terminals. Access to both traditional
+ pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
+ with this option. The assignment of UML devices to host devices
+ will be announced in the kernel message log.
+ It is safe to say 'Y' here.
config TTY_CHAN
bool "tty channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to host terminals. Access to both virtual consoles
+ (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
+ /dev/pts/*) are controlled by this option.
+ It is safe to say 'Y' here.
config XTERM_CHAN
bool "xterm channel support"
+ help
+ This option enables support for attaching UML consoles and serial
+ lines to xterms. Each UML device so assigned will be brought up in
+ its own xterm.
+ If you disable this option, then CONFIG_PT_PROXY will be disabled as
+ well, since UML's gdb currently requires an xterm.
+ It is safe to say 'Y' here.
config CON_ZERO_CHAN
string "Default main console channel initialization"
default "fd:0,fd:1"
+ help
+ This is the string describing the channel to which the main console
+ will be attached by default. This value can be overridden from the
+ command line. The default value is "fd:0,fd:1", which attaches the
+ main console to stdin and stdout.
+ It is safe to leave this unchanged.
config CON_CHAN
string "Default console channel initialization"
default "xterm"
+ help
+ This is the string describing the channel to which all consoles
+ except the main console will be attached by default. This value can
+ be overridden from the command line. The default value is "xterm",
+ which brings them up in xterms.
+ It is safe to leave this unchanged, although you may wish to change
+ this if you expect the UML that you build to be run in environments
+ which don't have X or xterm available.
config SSL_CHAN
string "Default serial line channel initialization"
default "pty"
+ help
+ This is the string describing the channel to which the serial lines
+ will be attached by default. This value can be overridden from the
+ command line. The default value is "pty", which attaches them to
+ traditional pseudo-terminals.
+ It is safe to leave this unchanged, although you may wish to change
+ this if you expect the UML that you build to be run in environments
+ which don't have a set of /dev/pty* devices.
config UNIX98_PTYS
bool "Unix98 PTY support"
@@ -63,6 +131,11 @@ config UML_WATCHDOG
config UML_SOUND
tristate "Sound support"
+ help
+ This option enables UML sound support. If enabled, it will pull in
+ soundcore and the UML hostaudio relay, which acts as a intermediary
+ between the host's dsp and mixer devices and the UML sound system.
+ It is safe to say 'Y' here.
config SOUND
tristate
@@ -72,8 +145,5 @@ config HOSTAUDIO
tristate
default UML_SOUND
-config TTY_LOG
- bool "Enable tty logging"
-
endmenu
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net
index ba311513abc3..443a74bd622d 100644
--- a/arch/um/Kconfig_net
+++ b/arch/um/Kconfig_net
@@ -5,30 +5,177 @@ menu "Network Devices"
# UML virtual driver
config UML_NET
bool "Virtual network device"
+ help
+ While the User-Mode port cannot directly talk to any physical
+ hardware devices, this choice and the following transport options
+ provide one or more virtual network devices through which the UML
+ kernels can talk to each other, the host, and with the host's help,
+ machines on the outside world.
+
+ For more information, including explanations of the networking and
+ sample configurations, see
+ <http://user-mode-linux.sourceforge.net/networking.html>.
+
+ If you'd like to be able to enable networking in the User-Mode
+ linux environment, say Y; otherwise say N. Note that you must
+ enable at least one of the following transport options to actually
+ make use of UML networking.
config UML_NET_ETHERTAP
bool "Ethertap transport"
depends on UML_NET
+ help
+ The Ethertap User-Mode Linux network transport allows a single
+ running UML to exchange packets with its host over one of the
+ host's Ethertap devices, such as /dev/tap0. Additional running
+ UMLs can use additional Ethertap devices, one per running UML.
+ While the UML believes it's on a (multi-device, broadcast) virtual
+ Ethernet network, it's in fact communicating over a point-to-point
+ link with the host.
+
+ To use this, your host kernel must have support for Ethertap
+ devices. Also, if your host kernel is 2.4.x, it must have
+ CONFIG_NETLINK_DEV configured as Y or M.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Ethertap
+ networking.
+
+ If you'd like to set up an IP network with the host and/or the
+ outside world, say Y to this, the Daemon Transport and/or the
+ Slip Transport. You'll need at least one of them, but may choose
+ more than one without conflict. If you don't need UML networking,
+ say N.
config UML_NET_TUNTAP
bool "TUN/TAP transport"
depends on UML_NET
+ help
+ The UML TUN/TAP network transport allows a UML instance to exchange
+ packets with the host over a TUN/TAP device. This option will only
+ work with a 2.4 host, unless you've applied the TUN/TAP patch to
+ your 2.2 host kernel.
+
+ To use this transport, your host kernel must have support for TUN/TAP
+ devices, either built-in or as a module.
config UML_NET_SLIP
bool "SLIP transport"
depends on UML_NET
+ help
+ The slip User-Mode Linux network transport allows a running UML to
+ network with its host over a point-to-point link. Unlike Ethertap,
+ which can carry any Ethernet frame (and hence even non-IP packets),
+ the slip transport can only carry IP packets.
+
+ To use this, your host must support slip devices.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html>. That site
+ has examples of the UML command line to use to enable slip
+ networking, and details of a few quirks with it.
+
+ The Ethertap Transport is preferred over slip because of its
+ limitations. If you prefer slip, however, say Y here. Otherwise
+ choose the Multicast transport (to network multiple UMLs on
+ multiple hosts), Ethertap (to network with the host and the
+ outside world), and/or the Daemon transport (to network multiple
+ UMLs on a single host). You may choose more than one without
+ conflict. If you don't need UML networking, say N.
config UML_NET_DAEMON
bool "Daemon transport"
depends on UML_NET
+ help
+ This User-Mode Linux network transport allows one or more running
+ UMLs on a single host to communicate with each other, but not to
+ the host.
+
+ To use this form of networking, you'll need to run the UML
+ networking daemon on the host.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Daemon
+ networking.
+
+ If you'd like to set up a network with other UMLs on a single host,
+ say Y. If you need a network between UMLs on multiple physical
+ hosts, choose the Multicast Transport. To set up a network with
+ the host and/or other IP machines, say Y to the Ethertap or Slip
+ transports. You'll need at least one of them, but may choose
+ more than one without conflict. If you don't need UML networking,
+ say N.
config UML_NET_MCAST
bool "Multicast transport"
depends on UML_NET
+ help
+ This Multicast User-Mode Linux network transport allows multiple
+ UMLs (even ones running on different host machines!) to talk to
+ each other over a virtual ethernet network. However, it requires
+ at least one UML with one of the other transports to act as a
+ bridge if any of them need to be able to talk to their hosts or any
+ other IP machines.
+
+ To use this, your host kernel(s) must support IP Multicasting.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable Multicast
+ networking, and notes about the security of this approach.
+
+ If you need UMLs on multiple physical hosts to communicate as if
+ they shared an Ethernet network, say Y. If you need to communicate
+ with other IP machines, make sure you select one of the other
+ transports (possibly in addition to Multicast; they're not
+ exclusive). If you don't need to network UMLs say N to each of
+ the transports.
config UML_NET_PCAP
bool "pcap transport"
depends on UML_NET
+ help
+ The pcap transport makes a pcap packet stream on the host look
+ like an ethernet device inside UML. This is useful for making
+ UML act as a network monitor for the host. You must have libcap
+ installed in order to build the pcap transport into UML.
+
+ For more information, see
+ <http://user-mode-linux.sourceforge.net/networking.html> That site
+ has examples of the UML command line to use to enable this option.
+
+ If you intend to use UML as a network monitor for the host, say
+ Y here. Otherwise, say N.
+
+config UML_NET_SLIRP
+ bool "SLiRP transport"
+ depends on UML_NET
+ help
+ The SLiRP User-Mode Linux network transport allows a running UML
+ to network by invoking a program that can handle SLIP encapsulated
+ packets. This is commonly (but not limited to) the application
+ known as SLiRP, a program that can re-socket IP packets back onto
+ the host on which it is run. Only IP packets are supported,
+ unlike other network transports that can handle all Ethernet
+ frames. In general, slirp allows the UML the same IP connectivity
+ to the outside world that the host user is permitted, and unlike
+ other transports, SLiRP works without the need of root level
+ privleges, setuid binaries, or SLIP devices on the host. This
+ also means not every type of connection is possible, but most
+ situations can be accomodated with carefully crafted slirp
+ commands that can be passed along as part of the network device's
+ setup string. The effect of this transport on the UML is similar
+ that of a host behind a firewall that masquerades all network
+ connections passing through it (but is less secure).
+
+ To use this you should first have slirp compiled somewhere
+ accessible on the host, and have read its documentation. If you
+ don't need UML networking, say N.
+
+ Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
+
# Below are hardware-independent drivers mirrored from
# drivers/net/Config.in. It would be nice if Linux
diff --git a/arch/um/Makefile b/arch/um/Makefile
index e4ad81702045..6fd0df8cd4e3 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -1,3 +1,8 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
ARCH_DIR = arch/um
OS := $(shell uname -s)
@@ -11,37 +16,31 @@ include/linux/version.h: arch/$(ARCH)/Makefile
# EXTRAVERSION...
MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
-MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot
-
ifeq ($(CONFIG_DEBUGSYM),y)
-DEBUG = -g
CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
endif
-ifeq ($(CONFIG_GCOV),y)
-CFLAGS += -fprofile-arcs -ftest-coverage
-endif
-
-ifeq ($(CONFIG_GPROF), y)
-PROFILE += -pg -DPROFILING
-LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
-endif
+CFLAGS-$(CONFIG_DEBUGSYM) += -g
+CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
+CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
+LINK-$(CONFIG_GPROF) += $(PROFILE) -Wl,--wrap,__monstartup
core-y += $(ARCH_DIR)/kernel/ \
$(ARCH_DIR)/drivers/ \
$(ARCH_DIR)/sys-$(SUBARCH)/
-core-$(CONFIG_PT_PROXY) += $(ARCH_DIR)/ptproxy/
-
-ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
+ARCH_INCLUDE = -I$(ARCH_DIR)/include
+MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \
+ -I$(ARCH_DIR)/kernel/skas/include
# -Derrno=kernel_errno - This turns all kernel references to errno into
# kernel_errno to separate them from the libc errno. This allows -fno-common
# in CFLAGS. Otherwise, it would cause ld to complain about the two different
# errnos.
-CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
- -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno
+CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
+ $(MODE_INCLUDE)
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
@@ -51,10 +50,16 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
include/asm-um/sigcontext.h include/asm-um/processor.h \
include/asm-um/ptrace.h include/asm-um/arch-signal.h
-ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
- $(SYMLINK_HEADERS)
+ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
+ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
+
+ifeq ($(CONFIG_MODE_SKAS), y)
+GEN_HEADERS = $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
-GEN_HEADERS = $(ARCH_DIR)/include/task.h
+$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
+endif
+
+GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
include $(ARCH_DIR)/Makefile-$(SUBARCH)
include $(ARCH_DIR)/Makefile-os-$(OS)
@@ -62,9 +67,9 @@ include $(ARCH_DIR)/Makefile-os-$(OS)
$(ARCH_DIR)/vmlinux.lds.S :
touch $@
-prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS)
+prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
-LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o
+LDFLAGS_vmlinux = -r
vmlinux: $(ARCH_DIR)/main.o
@@ -74,18 +79,21 @@ $(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S scripts FORCE
AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \
-DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum
-linux: arch/um/uml.lds.s vmlinux
- $(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \
- $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil
+linux: $(ARCH_DIR)/uml.lds.s vmlinux
+ $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -static $(LINK-y) $(LINK_WRAPS) \
+ -o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
-USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
+USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
+ $(MODE_INCLUDE)
# To get a definition of F_SETSIG
USER_CFLAGS += -D_GNU_SOURCE
+CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
+
$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
@@ -106,11 +114,9 @@ archclean: sysclean
find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
-o -name '*.gcov' \) -type f -print | xargs rm -f
rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
- @$(MAKEBOOT) clean
archdep:
for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done
- @$(MAKEBOOT) dep
$(SYMLINK_HEADERS):
cd $(TOPDIR)/$(dir $@) ; \
@@ -119,18 +125,28 @@ $(SYMLINK_HEADERS):
include/asm-um/arch:
cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
-arch/um/include/sysdep:
- cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
+$(ARCH_DIR)/include/sysdep:
+ cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep
-arch/um/os:
+$(ARCH_DIR)/os:
cd $(ARCH_DIR) && ln -sf os-$(OS) os
+$(ARCH_DIR)/include/uml-config.h :
+ ln -sf $(TOPDIR)/include/linux/autoconf.h $@
+
$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
$< > $@
-$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ;
+$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
+ $< > $@
+
+$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \
+ $(ARCH_DIR)/util FORCE ;
$(ARCH_DIR)/util: FORCE
@$(call descend,$@,)
+$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
+ $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
+
export SUBARCH USER_CFLAGS OS
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index e4a66c4fbacf..3bd90fbdb7e0 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -21,13 +21,13 @@ prepare: $(SYS_HEADERS)
$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
$< > $@
-$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
+$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
$< > $@
$(SYS_UTIL_DIR)/mk_sc: FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@)
-$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) FORCE ;
+$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@)
$(SYS_UTIL_DIR): include/asm FORCE
diff --git a/arch/um/boot/Makefile b/arch/um/boot/Makefile
deleted file mode 100644
index f5dc182a5fb4..000000000000
--- a/arch/um/boot/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-dep:
-
-clean:
diff --git a/arch/um/config_block.in b/arch/um/config_block.in
deleted file mode 100644
index 419bb713354a..000000000000
--- a/arch/um/config_block.in
+++ /dev/null
@@ -1,16 +0,0 @@
-mainmenu_option next_comment
-comment 'Block Devices'
-
-bool 'Virtual block device' CONFIG_BLK_DEV_UBD
-dep_bool ' Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
- int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
-fi
-dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
-
-tristate 'Example IO memory driver' CONFIG_MMAPPER
-
-endmenu
diff --git a/arch/um/config_char.in b/arch/um/config_char.in
deleted file mode 100644
index dfb87d66b8de..000000000000
--- a/arch/um/config_char.in
+++ /dev/null
@@ -1,37 +0,0 @@
-mainmenu_option next_comment
-comment 'Character Devices'
-
-define_bool CONFIG_STDIO_CONSOLE y
-
-bool 'Virtual serial line' CONFIG_SSL
-
-bool 'file descriptor channel support' CONFIG_FD_CHAN
-bool 'null channel support' CONFIG_NULL_CHAN
-bool 'port channel support' CONFIG_PORT_CHAN
-bool 'pty channel support' CONFIG_PTY_CHAN
-bool 'tty channel support' CONFIG_TTY_CHAN
-bool 'xterm channel support' CONFIG_XTERM_CHAN
-string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \
- "fd:0,fd:1"
-string 'Default console channel initialization' CONFIG_CON_CHAN "xterm"
-string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty"
-
-
-bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-fi
-
-bool 'Watchdog Timer Support' CONFIG_WATCHDOG
-dep_bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \
- $CONFIG_WATCHDOG
-dep_tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG
-dep_tristate ' UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG
-
-tristate 'Sound support' CONFIG_UML_SOUND
-define_tristate CONFIG_SOUND $CONFIG_UML_SOUND
-define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND
-
-bool 'Enable tty logging' CONFIG_TTY_LOG
-
-endmenu
diff --git a/arch/um/config_net.in b/arch/um/config_net.in
deleted file mode 100644
index f1f6a6e9b13f..000000000000
--- a/arch/um/config_net.in
+++ /dev/null
@@ -1,46 +0,0 @@
-mainmenu_option next_comment
-comment 'Network Devices'
-
-# UML virtual driver
-bool 'Virtual network device' CONFIG_UML_NET
-
-dep_bool ' Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET
-dep_bool ' TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET
-dep_bool ' SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
-dep_bool ' Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
-dep_bool ' Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
-dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET
-
-# Below are hardware-independent drivers mirrored from
-# drivers/net/Config.in. It would be nice if Linux
-# had HW independent drivers separated from the other
-# but it does not. Until then each non-ISA/PCI arch
-# needs to provide it's own menu of network drivers
-
-tristate 'Dummy net driver support' CONFIG_DUMMY
-tristate 'Bonding driver support' CONFIG_BONDING
-tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_NETLINK" = "y" ]; then
- tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
- fi
-fi
-
-tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
-if [ ! "$CONFIG_PPP" = "n" ]; then
- dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
- dep_bool ' PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
- dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
- dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
- dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
- dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
- dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL
-fi
-
-tristate 'SLIP (serial line) support' CONFIG_SLIP
-dep_bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP
-dep_bool ' Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP
-dep_bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP
-
-endmenu
diff --git a/arch/um/config_scsi.in b/arch/um/config_scsi.in
deleted file mode 100644
index ed363965b73f..000000000000
--- a/arch/um/config_scsi.in
+++ /dev/null
@@ -1,30 +0,0 @@
-comment 'SCSI support type (disk, tape, CD-ROM)'
-
-dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-
-if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
- int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
-fi
-
-dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-
-dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
-
-if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
- bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
- int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
-fi
-dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
-
-comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES
-#fi
-
-bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
-
-bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
-bool ' SCSI logging facility' CONFIG_SCSI_LOGGING
-
-dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index bd963ccdc7e8..8e72f9032ab6 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -5,23 +5,14 @@
CHAN_OBJS := chan_kern.o chan_user.o line.o
-# This nonsense is due to kbuild. In the 2.4 build, I stick -lpcap in
-# pcap-objs, and that is just included in the link command. The 2.5 kbuild
-# filters out everything from pcap-objs which are not in the built-in.o
-# dependencies, which are $(obj-y). So, -lpcap must be in $(obj-y), too.
-# However, make magically expands -lfoo prerequisites into /usr/lib/libfoo.a
-# file names. This causes the kbuild filtering to filter the -lpcap from
-# pcap-objs, causing the link to fail.
-# So, what this does is figure out by hand (crudely) what file -lpcap really
-# is and just use it.
-
-PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.a; do \
- [ -f $$f ] && echo $$f ; done | head -1)
+# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
+# in to pcap.o
slip-objs := slip_kern.o slip_user.o
+slirp-objs := slirp_kern.o slirp_user.o
daemon-objs := daemon_kern.o daemon_user.o
mcast-objs := mcast_kern.o mcast_user.o
-pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
+#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o hostaudio_user.o
@@ -34,9 +25,10 @@ export-objs := mconsole_kern.o
obj-y =
obj-$(CONFIG_SSL) += ssl.o
obj-$(CONFIG_UML_NET_SLIP) += slip.o
+obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
obj-$(CONFIG_UML_NET_MCAST) += mcast.o
-obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
+#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
obj-$(CONFIG_UML_NET) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MMAPPER) += mmapper_kern.o
@@ -50,8 +42,6 @@ obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o
-CFLAGS_pcap_user.o = -I/usr/include/pcap
-
obj-y += stdio_console.o $(CHAN_OBJS)
USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
@@ -61,7 +51,7 @@ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean:
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 46a84e8e916c..119cce1bb689 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -24,7 +24,8 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
return(NULL);
}
-static int not_configged_open(int input, int output, int primary, void *data)
+static int not_configged_open(int input, int output, int primary, void *data,
+ char **dev_out)
{
printk(KERN_ERR "Using a channel type which is configured out of "
"UML\n");
@@ -112,7 +113,8 @@ static int open_one_chan(struct chan *chan, int input, int output, int primary)
if(chan->opened) return(0);
if(chan->ops->open == NULL) fd = 0;
- else fd = (*chan->ops->open)(input, output, primary, chan->data);
+ else fd = (*chan->ops->open)(input, output, primary, chan->data,
+ &chan->dev);
if(fd < 0) return(fd);
chan->fd = fd;
@@ -258,6 +260,66 @@ void free_chan(struct list_head *chans)
}
}
+static int one_chan_config_string(struct chan *chan, char *str, int size,
+ char **error_out)
+{
+ int n = 0;
+
+ CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
+
+ if(chan->dev == NULL){
+ CONFIG_CHUNK(str, size, n, "", 1);
+ return(n);
+ }
+
+ CONFIG_CHUNK(str, size, n, ":", 0);
+ CONFIG_CHUNK(str, size, n, chan->dev, 0);
+
+ return(n);
+}
+
+static int chan_pair_config_string(struct chan *in, struct chan *out,
+ char *str, int size, char **error_out)
+{
+ int n;
+
+ n = one_chan_config_string(in, str, size, error_out);
+ str += n;
+ size -= n;
+
+ if(in == out){
+ CONFIG_CHUNK(str, size, n, "", 1);
+ return(n);
+ }
+
+ CONFIG_CHUNK(str, size, n, ",", 1);
+ n = one_chan_config_string(out, str, size, error_out);
+ str += n;
+ size -= n;
+ CONFIG_CHUNK(str, size, n, "", 1);
+
+ return(n);
+}
+
+int chan_config_string(struct list_head *chans, char *str, int size,
+ char **error_out)
+{
+ struct list_head *ele;
+ struct chan *chan, *in = NULL, *out = NULL;
+
+ list_for_each(ele, chans){
+ chan = list_entry(ele, struct chan, list);
+ if(!chan->primary)
+ continue;
+ if(chan->input)
+ in = chan;
+ if(chan->output)
+ out = chan;
+ }
+
+ return(chan_pair_config_string(in, out, str, size, error_out));
+}
+
struct chan_type {
char *key;
struct chan_ops *ops;
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 79879f30aef5..e06f20a14877 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -19,6 +19,8 @@
#include "user.h"
#include "helper.h"
#include "os.h"
+#include "choose-mode.h"
+#include "mode.h"
void generic_close(int fd, void *unused)
{
@@ -144,32 +146,6 @@ static int winch_thread(void *arg)
}
}
-static int tracer_winch[2];
-
-static void tracer_winch_handler(int sig)
-{
- char c = 1;
-
- if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
- printk("tracer_winch_handler - write failed, errno = %d\n",
- errno);
-}
-
-/* Called only by the tracing thread during initialization */
-
-void setup_tracer_winch(void)
-{
- int err;
-
- err = os_pipe(tracer_winch, 1, 1);
- if(err){
- printk("setup_tracer_winch : os_pipe failed, errno = %d\n",
- -err);
- return;
- }
- signal(SIGWINCH, tracer_winch_handler);
-}
-
static int winch_tramp(int fd, void *device_data, int *fd_out)
{
struct winch_data data;
@@ -212,9 +188,8 @@ void register_winch(int fd, void *device_data)
if(!isatty(fd)) return;
pid = tcgetpgrp(fd);
- if(pid == tracing_pid)
- register_winch_irq(tracer_winch[0], fd, -1, device_data);
- else if(pid == -1){
+ if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) &&
+ (pid == -1)){
thread = winch_tramp(fd, device_data, &thread_fd);
if(fd != -1){
register_winch_irq(thread_fd, fd, thread, device_data);
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index e31620d15a77..60fc63adce4a 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -15,6 +15,7 @@ struct fd_chan {
int fd;
int raw;
struct termios tt;
+ char str[sizeof("1234567890\0")];
};
void *fd_init(char *str, int device, struct chan_opts *opts)
@@ -30,7 +31,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
}
str++;
n = strtoul(str, &end, 0);
- if(*end != '\0'){
+ if((*end != '\0') || (end == str)){
printk("fd_init : couldn't parse file descriptor '%s'\n", str);
return(NULL);
}
@@ -40,7 +41,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
return(data);
}
-int fd_open(int input, int output, int primary, void *d)
+int fd_open(int input, int output, int primary, void *d, char **dev_out)
{
struct fd_chan *data = d;
@@ -48,6 +49,8 @@ int fd_open(int input, int output, int primary, void *d)
tcgetattr(data->fd, &data->tt);
raw(data->fd, 0);
}
+ sprintf(data->str, "%d", data->fd);
+ *dev_out = data->str;
return(data->fd);
}
@@ -69,6 +72,7 @@ int fd_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops fd_ops = {
+ type: "fd",
init: fd_init,
open: fd_open,
close: fd_close,
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 837c07f41669..576f3f655a04 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -8,11 +8,13 @@
#include "linux/list.h"
#include "linux/devfs_fs_kernel.h"
#include "asm/irq.h"
+#include "asm/uaccess.h"
#include "chan_kern.h"
#include "irq_user.h"
#include "line.h"
#include "kern.h"
#include "user_util.h"
+#include "kern_util.h"
#include "os.h"
#define LINE_BUFSIZE 4096
@@ -87,15 +89,26 @@ static int flush_buffer(struct line *line)
return(line->head == line->tail);
}
-int line_write(struct line *lines, struct tty_struct *tty, const char *buf,
- int len)
+int line_write(struct line *lines, struct tty_struct *tty, int from_user,
+ const char *buf, int len)
{
struct line *line;
+ char *new;
unsigned long flags;
int n, err, i;
if(tty->stopped) return 0;
+ if(from_user){
+ new = kmalloc(len, GFP_KERNEL);
+ if(new == NULL)
+ return(0);
+ n = copy_from_user(new, buf, len);
+ if(n == len)
+ return(-EFAULT);
+ buf = new;
+ }
+
i = minor(tty->device) - tty->driver.minor_start;
line = &lines[i];
@@ -281,7 +294,7 @@ void close_lines(struct line *lines, int nlines)
close_chan(&lines[i].chan_list);
}
-void line_setup(struct line *lines, int num, char *init)
+int line_setup(struct line *lines, int num, char *init, int all_allowed)
{
int i, n;
char *end;
@@ -292,12 +305,36 @@ void line_setup(struct line *lines, int num, char *init)
if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
- return;
+ return(1);
}
init = end;
}
init++;
- if(n == -1){
+ if((n >= 0) && (n >= num)){
+ printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
+ n, num);
+ return(1);
+ }
+ else if(n >= 0){
+ if(lines[n].count > 0){
+ printk("line_setup - device %d is open\n", n);
+ return(1);
+ }
+ if(lines[n].init_pri <= INIT_ONE){
+ lines[n].init_pri = INIT_ONE;
+ if(!strcmp(init, "none")) lines[n].valid = 0;
+ else {
+ lines[n].init_str = init;
+ lines[n].valid = 1;
+ }
+ }
+ }
+ else if(!all_allowed){
+ printk("line_setup - can't configure all devices from "
+ "mconsole\n");
+ return(1);
+ }
+ else {
for(i = 0; i < num; i++){
if(lines[i].init_pri <= INIT_ALL){
lines[i].init_pri = INIT_ALL;
@@ -309,14 +346,57 @@ void line_setup(struct line *lines, int num, char *init)
}
}
}
- else if(lines[n].init_pri <= INIT_ONE){
- lines[n].init_pri = INIT_ONE;
- if(!strcmp(init, "none")) lines[n].valid = 0;
- else {
- lines[n].init_str = init;
- lines[n].valid = 1;
- }
+ return(0);
+}
+
+int line_config(struct line *lines, int num, char *str)
+{
+ char *new = uml_strdup(str);
+
+ if(new == NULL){
+ printk("line_config - uml_strdup failed\n");
+ return(-ENOMEM);
}
+ return(line_setup(lines, num, new, 0));
+}
+
+int line_get_config(char *name, struct line *lines, int num, char *str,
+ int size, char **error_out)
+{
+ struct line *line;
+ char *end;
+ int dev, n = 0;
+
+ dev = simple_strtoul(name, &end, 0);
+ if((*end != '\0') || (end == name)){
+ *error_out = "line_setup failed to parse device number";
+ return(0);
+ }
+
+ if((dev < 0) || (dev >= num)){
+ *error_out = "device number of of range";
+ return(0);
+ }
+
+ line = &lines[dev];
+ down(&line->sem);
+
+ if(!line->valid)
+ CONFIG_CHUNK(str, size, n, "none", 1);
+ else if(line->count == 0)
+ CONFIG_CHUNK(str, size, n, line->init_str, 1);
+ else n = chan_config_string(&line->chan_list, str, size, error_out);
+
+ up(&line->sem);
+ return(n);
+}
+
+int line_remove(struct line *lines, int num, char *str)
+{
+ char config[sizeof("conxxxx=none\0")];
+
+ sprintf(config, "%s=none", str);
+ return(line_setup(lines, num, config, 0));
}
void line_register_devfs(struct lines *set, struct line_driver *line_driver,
@@ -366,6 +446,8 @@ void line_register_devfs(struct lines *set, struct line_driver *line_driver,
if(!lines[i].valid)
tty_unregister_devfs(driver, driver->minor_start + i);
}
+
+ mconsole_register_dev(&line_driver->mc);
}
void lines_init(struct line *lines, int nlines)
@@ -451,7 +533,7 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
close(winch->fd);
- if(winch->pid != -1) os_kill_process(winch->pid);
+ if(winch->pid != -1) os_kill_process(winch->pid, 0);
}
}
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 25158ba650c2..a0cbc72b8cd3 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -92,7 +92,7 @@ int mcast_setup(char *str, char **mac_out, void *data)
if(port_str != NULL){
n = simple_strtoul(port_str, &last, 10);
- if(*last != '\0'){
+ if((*last != '\0') || (last == port_str)){
printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
port_str);
return(0);
@@ -102,7 +102,7 @@ int mcast_setup(char *str, char **mac_out, void *data)
if(ttl_str != NULL){
init->ttl = simple_strtoul(ttl_str, &last, 10);
- if(*last != '\0'){
+ if((*last != '\0') || (last == ttl_str)){
printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
ttl_str);
return(0);
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 49c1773e0c9b..8ba898759587 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -108,6 +108,7 @@ void mconsole_version(struct mc_request *req)
reboot - Reboot UML
config <dev>=<config> - Add a new device to UML;
same syntax as command line
+ config <dev> - Query the configuration of a device
remove <dev> - Remove a device from UML
sysrq <letter> - Performs the SysRq action controlled by the letter
cad - invoke the Ctl-Alt-Del handler
@@ -181,10 +182,56 @@ static struct mc_device *mconsole_find_dev(char *name)
return(NULL);
}
+#define CONFIG_BUF_SIZE 64
+
+static void mconsole_get_config(int (*get_config)(char *, char *, int,
+ char **),
+ struct mc_request *req, char *name)
+{
+ char default_buf[CONFIG_BUF_SIZE], *error, *buf;
+ int n, size;
+
+ if(get_config == NULL){
+ mconsole_reply(req, "No get_config routine defined", 1, 0);
+ return;
+ }
+
+ error = NULL;
+ size = sizeof(default_buf)/sizeof(default_buf[0]);
+ buf = default_buf;
+
+ while(1){
+ n = (*get_config)(name, buf, size, &error);
+ if(error != NULL){
+ mconsole_reply(req, error, 1, 0);
+ goto out;
+ }
+
+ if(n <= size){
+ mconsole_reply(req, buf, 0, 0);
+ goto out;
+ }
+
+ if(buf != default_buf)
+ kfree(buf);
+
+ size = n;
+ buf = kmalloc(size, GFP_KERNEL);
+ if(buf == NULL){
+ mconsole_reply(req, "Failed to allocate buffer", 1, 0);
+ return;
+ }
+ }
+ out:
+ if(buf != default_buf)
+ kfree(buf);
+
+}
+
void mconsole_config(struct mc_request *req)
{
struct mc_device *dev;
- char *ptr = req->request.data;
+ char *ptr = req->request.data, *name;
int err;
ptr += strlen("config");
@@ -194,8 +241,17 @@ void mconsole_config(struct mc_request *req)
mconsole_reply(req, "Bad configuration option", 1, 0);
return;
}
- err = (*dev->config)(&ptr[strlen(dev->name)]);
- mconsole_reply(req, "", err, 0);
+
+ name = &ptr[strlen(dev->name)];
+ ptr = name;
+ while((*ptr != '=') && (*ptr != '\0'))
+ ptr++;
+
+ if(*ptr == '='){
+ err = (*dev->config)(name);
+ mconsole_reply(req, "", err, 0);
+ }
+ else mconsole_get_config(dev->get_config, req, name);
}
void mconsole_remove(struct mc_request *req)
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index deef1a0a75e3..f6bda1b3b1fe 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -39,7 +39,6 @@ static int uml_net_rx(struct net_device *dev)
/* If we can't allocate memory, try again next round. */
if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
lp->stats.rx_dropped++;
- reactivate_fd(lp->fd, UM_ETH_IRQ);
return 0;
}
@@ -48,7 +47,6 @@ static int uml_net_rx(struct net_device *dev)
skb->mac.raw = skb->data;
pkt_len = (*lp->read)(lp->fd, &skb, lp);
- reactivate_fd(lp->fd, UM_ETH_IRQ);
if (pkt_len > 0) {
skb_trim(skb, pkt_len);
skb->protocol = (*lp->protocol)(skb);
@@ -69,18 +67,22 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct uml_net_private *lp = dev->priv;
int err;
- if (netif_running(dev)) {
- spin_lock(&lp->lock);
- while((err = uml_net_rx(dev)) > 0) ;
- if(err < 0) {
- printk(KERN_ERR
- "Device '%s' read returned %d, shutting it "
- "down\n", dev->name, err);
- dev->flags &= ~IFF_UP;
- dev_close(dev);
- }
- spin_unlock(&lp->lock);
+ if(!netif_running(dev))
+ return;
+
+ spin_lock(&lp->lock);
+ while((err = uml_net_rx(dev)) > 0) ;
+ if(err < 0) {
+ printk(KERN_ERR
+ "Device '%s' read returned %d, shutting it down\n",
+ dev->name, err);
+ dev_close(dev);
+ goto out;
}
+ reactivate_fd(lp->fd, UM_ETH_IRQ);
+
+ out:
+ spin_unlock(&lp->lock);
}
static int uml_net_open(struct net_device *dev)
@@ -250,6 +252,37 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
+/*
+ * default do nothing hard header packet routines for struct net_device init.
+ * real ethernet transports will overwrite with real routines.
+ */
+static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ return(0); /* no change */
+}
+
+static int uml_net_rebuild_header(struct sk_buff *skb)
+{
+ return(0); /* ignore */
+}
+
+static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+ return(-1); /* fail */
+}
+
+static void uml_net_header_cache_update(struct hh_cache *hh,
+ struct net_device *dev, unsigned char * haddr)
+{
+ /* ignore */
+}
+
+static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ return(0); /* nothing */
+}
+
static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
static struct list_head devices = LIST_HEAD_INIT(devices);
@@ -261,21 +294,25 @@ static int eth_configure(int n, void *init, char *mac,
struct uml_net_private *lp;
int save, err, size;
+ size = transport->private_size + sizeof(struct uml_net_private) +
+ sizeof(((struct uml_net_private *) 0)->user);
+
device = kmalloc(sizeof(*device), GFP_KERNEL);
if(device == NULL){
printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
return(1);
}
+ *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list),
+ .dev = NULL,
+ .index = n,
+ .mac = { [ 0 ... 5 ] = 0 },
+ .have_mac = 0 });
+
spin_lock(&devices_lock);
list_add(&device->list, &devices);
spin_unlock(&devices_lock);
- device->index = n;
-
- size = transport->private_size + sizeof(struct uml_net_private) +
- sizeof(((struct uml_net_private *) 0)->user);
-
if(setup_etheraddr(mac, device->mac))
device->have_mac = 1;
@@ -290,10 +327,18 @@ static int eth_configure(int n, void *init, char *mac,
printk(KERN_ERR "eth_configure: failed to allocate device\n");
return(1);
}
+ memset(dev, 0, sizeof(*dev) + size);
+
snprintf(dev->name, sizeof(dev->name), "eth%d", n);
dev->priv = (void *) &dev[1];
device->dev = dev;
+ dev->hard_header = uml_net_hard_header;
+ dev->rebuild_header = uml_net_rebuild_header;
+ dev->hard_header_cache = uml_net_header_cache;
+ dev->header_cache_update= uml_net_header_cache_update;
+ dev->hard_header_parse = uml_net_header_parse;
+
(*transport->kern->init)(dev, init);
dev->mtu = transport->user->max_packet;
@@ -308,32 +353,6 @@ static int eth_configure(int n, void *init, char *mac,
dev->do_ioctl = uml_net_ioctl;
dev->watchdog_timeo = (HZ >> 1);
dev->irq = UM_ETH_IRQ;
- dev->init = NULL;
- dev->master = NULL;
- dev->neigh_setup = NULL;
- dev->owner = NULL;
- dev->state = 0;
- dev->next_sched = 0;
- dev->get_wireless_stats = 0;
- dev->wireless_handlers = 0;
- dev->gflags = 0;
- dev->mc_list = NULL;
- dev->mc_count = 0;
- dev->promiscuity = 0;
- dev->atalk_ptr = NULL;
- dev->ip_ptr = NULL;
- dev->dn_ptr = NULL;
- dev->ip6_ptr = NULL;
- dev->ec_ptr = NULL;
- atomic_set(&dev->refcnt, 0);
- dev->features = 0;
- dev->uninit = NULL;
- dev->destructor = NULL;
- dev->set_config = NULL;
- dev->accept_fastpath = 0;
- dev->br_port = 0;
- dev->mem_start = 0;
- dev->mem_end = 0;
rtnl_lock();
err = register_netdevice(dev);
@@ -372,6 +391,7 @@ static int eth_configure(int n, void *init, char *mac,
if(transport->user->init)
(*transport->user->init)(&lp->user, dev);
+
if(device->have_mac)
set_ether_mac(dev, device->mac);
return(0);
@@ -486,7 +506,6 @@ void register_transport(struct transport *new)
kfree(init);
}
list_del(&eth->list);
- return;
}
}
@@ -580,7 +599,7 @@ static int net_remove(char *str)
int n;
n = simple_strtoul(str, &end, 0);
- if(*end != '\0')
+ if((*end != '\0') || (end == str))
return(-1);
device = find_device(n);
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
index 08cc7b0a165e..6a41c213e0d6 100644
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -3,6 +3,7 @@
* Licensed under the GPL
*/
+#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include "chan_user.h"
@@ -15,8 +16,9 @@ void *null_init(char *str, int device, struct chan_opts *opts)
return(&null_chan);
}
-int null_open(int input, int output, int primary, void *d)
+int null_open(int input, int output, int primary, void *d, char **dev_out)
{
+ *dev_out = NULL;
return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
}
@@ -30,6 +32,7 @@ void null_free(void *data)
}
struct chan_ops null_ops = {
+ type: "null",
init: null_init,
open: null_open,
close: generic_close,
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 25a1c47c116f..15ce4f90ab95 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -32,8 +32,8 @@ struct port_list {
struct port_dev {
struct port_list *port;
int fd;
- int helper_pid;
- int telnetd_pid;
+ int helper_pid;
+ int telnetd_pid;
};
struct connection {
@@ -50,7 +50,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
struct connection *conn = data;
int fd;
- fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
+ fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
if(fd < 0){
if(fd == -EAGAIN)
return;
@@ -99,14 +99,13 @@ static int port_accept(struct port_list *port)
}
list_add(&conn->list, &port->pending);
- ret = 1;
- goto out;
+ return(1);
out_free:
kfree(conn);
out_close:
os_close_file(fd);
- if(pid != -1) os_kill_process(pid);
+ if(pid != -1) os_kill_process(pid, 0);
out:
return(ret);
}
@@ -191,9 +190,9 @@ void *port_data(int port_num)
goto out;
}
- *dev = ((struct port_dev) { port : port,
- fd : -1,
- helper_pid : -1 });
+ *dev = ((struct port_dev) { port : port,
+ fd : -1,
+ helper_pid : -1 });
goto out;
out_free:
@@ -210,9 +209,9 @@ void port_remove_dev(void *d)
struct port_dev *dev = d;
if(dev->helper_pid != -1)
- os_kill_process(dev->helper_pid);
+ os_kill_process(dev->helper_pid, 0);
if(dev->telnetd_pid != -1)
- os_kill_process(dev->telnetd_pid);
+ os_kill_process(dev->telnetd_pid, 0);
dev->helper_pid = -1;
}
@@ -275,8 +274,8 @@ void port_kern_free(void *d)
{
struct port_dev *dev = d;
- if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid);
- if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid);
+ if(dev->helper_pid != -1) os_kill_process(dev->helper_pid, 0);
+ if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid, 0);
kfree(dev);
}
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 35f163da9d32..3e0d3950ac1c 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -3,11 +3,12 @@
* Licensed under the GPL
*/
+#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <unistd.h>
-#include <string.h>
#include <termios.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -24,6 +25,7 @@ struct port_chan {
int raw;
struct termios tt;
void *kernel_data;
+ char dev[sizeof("32768\0")];
};
void *port_init(char *str, int device, struct chan_opts *opts)
@@ -40,7 +42,7 @@ void *port_init(char *str, int device, struct chan_opts *opts)
}
str++;
port = strtoul(str, &end, 0);
- if(*end != '\0'){
+ if((*end != '\0') || (end == str)){
printk("port_init : couldn't parse port '%s'\n", str);
return(NULL);
}
@@ -50,11 +52,12 @@ void *port_init(char *str, int device, struct chan_opts *opts)
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
*data = ((struct port_chan) { raw : opts->raw,
kernel_data : kern_data });
+ sprintf(data->dev, "%d", port);
return(data);
}
-int port_open(int input, int output, int primary, void *d)
+int port_open(int input, int output, int primary, void *d, char **dev_out)
{
struct port_chan *data = d;
int fd;
@@ -64,6 +67,7 @@ int port_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
+ *dev_out = data->dev;
return(fd);
}
@@ -91,6 +95,7 @@ void port_free(void *d)
}
struct chan_ops port_ops = {
+ type: "port",
init: port_init,
open: port_open,
close: port_close,
@@ -129,42 +134,6 @@ int port_listen_fd(int port)
return(err);
}
-int port_rcv_fd(int fd)
-{
- int new, n;
- char buf[CMSG_SPACE(sizeof(new))];
- struct msghdr msg;
- struct cmsghdr *cmsg;
-
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = NULL;
- msg.msg_iovlen = 0;
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- msg.msg_flags = 0;
-
- n = recvmsg(fd, &msg, 0);
- if(n < 0){
- printk("rcv_fd : recvmsg failed - errno = %d\n", errno);
- return(-1);
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if(cmsg == NULL){
- printk("rcv_fd didn't receive anything, error = %d\n", errno);
- return(-1);
- }
- if((cmsg->cmsg_level != SOL_SOCKET) ||
- (cmsg->cmsg_type != SCM_RIGHTS)){
- printk("rcv_fd didn't receive a descriptor\n");
- return(-1);
- }
-
- new = ((int *) CMSG_DATA(cmsg))[0];
- return(new);
-}
-
struct port_pre_exec_data {
int sock_fd;
int pipe_fd;
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 6054dd6aa9ac..213b35d1dcfc 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -19,6 +19,7 @@ struct pty_chan {
int dev;
int raw;
struct termios tt;
+ char dev_name[sizeof("/dev/pts/0123456\0")];
};
void *pty_chan_init(char *str, int device, struct chan_opts *opts)
@@ -32,9 +33,10 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts)
return(data);
}
-int pts_open(int input, int output, int primary, void *d)
+int pts_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
+ char *dev;
int fd;
if((fd = get_pty()) < 0){
@@ -45,7 +47,11 @@ int pts_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
- if(data->announce) (*data->announce)(ptsname(fd), data->dev);
+
+ dev = ptsname(fd);
+ sprintf(data->dev_name, "%s", dev);
+ *dev_out = data->dev_name;
+ if(data->announce) (*data->announce)(dev, data->dev);
return(fd);
}
@@ -94,7 +100,7 @@ static void grantpt_cb(void *arg)
info->err = errno;
}
-int pty_open(int input, int output, int primary, void *d)
+int pty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
int fd;
@@ -105,11 +111,14 @@ int pty_open(int input, int output, int primary, void *d)
if(fd < 0) return(-errno);
info.fd = fd;
- tracing_cb(grantpt_cb, &info);
+ initial_thread_cb(grantpt_cb, &info);
unlockpt(fd);
if(data->raw) raw(fd, 0);
if(data->announce) (*data->announce)(dev, data->dev);
+
+ sprintf(data->dev_name, "%s", dev);
+ *dev_out = data->dev_name;
return(fd);
}
@@ -121,6 +130,7 @@ int pty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops pty_ops = {
+ type: "pty",
init: pty_chan_init,
open: pty_open,
close: generic_close,
@@ -133,6 +143,7 @@ struct chan_ops pty_ops = {
};
struct chan_ops pts_ops = {
+ type: "pts",
init: pty_chan_init,
open: pts_open,
close: generic_close,
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
index 6fe5588e8a21..495f2f1b1420 100644
--- a/arch/um/drivers/slip.h
+++ b/arch/um/drivers/slip.h
@@ -2,6 +2,9 @@
#define __UM_SLIP_H
#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars + *
+ * terminating END char + initial END char */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
struct slip_data {
void *dev;
@@ -9,10 +12,9 @@ struct slip_data {
char *addr;
char *gate_addr;
int slave;
- /* two bytes each for a (pathological) max packet of escaped chars +
- * terminating END char + inital END char
- */
- char buf[2 * BUF_SIZE + 2];
+ char ibuf[ENC_BUF_SIZE];
+ char obuf[ENC_BUF_SIZE];
+ int more; /* more data: do not read fd until ibuf has been drained */
int pos;
int esc;
};
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 1ca56f563757..f498a83d9db5 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -1,3 +1,4 @@
+#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/stddef.h"
#include "linux/init.h"
@@ -24,21 +25,19 @@ void slip_init(struct net_device *dev, void *data)
{ name : { '\0' },
addr: NULL,
gate_addr : init->gate_addr,
- slave : 0,
- buf : { '\0' },
+ slave : -1,
+ ibuf : { '\0' },
+ obuf : { '\0' },
pos : 0,
esc : 0,
dev : dev });
- strncpy(dev->name, "umn", IFNAMSIZ);
dev->init = NULL;
dev->hard_header_len = 0;
dev->addr_len = 4;
dev->type = ARPHRD_ETHER;
dev->tx_queue_len = 256;
dev->flags = IFF_NOARP;
- if(register_netdev(dev))
- printk(KERN_ERR "Couldn't initialize umn\n");
printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
}
diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h
new file mode 100644
index 000000000000..7206361ace45
--- /dev/null
+++ b/arch/um/drivers/slip_proto.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_SLIP_PROTO_H__
+#define __UM_SLIP_PROTO_H__
+
+/* SLIP protocol characters. */
+#define SLIP_END 0300 /* indicates end of frame */
+#define SLIP_ESC 0333 /* indicates byte stuffing */
+#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
+#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
+
+static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
+{
+ int ret;
+
+ switch(c){
+ case SLIP_END:
+ *esc = 0;
+ ret=*pos;
+ *pos=0;
+ return(ret);
+ case SLIP_ESC:
+ *esc = 1;
+ return(0);
+ case SLIP_ESC_ESC:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_ESC;
+ }
+ break;
+ case SLIP_ESC_END:
+ if(*esc){
+ *esc = 0;
+ c = SLIP_END;
+ }
+ break;
+ }
+ buf[(*pos)++] = c;
+ return(0);
+}
+
+static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+ unsigned char *ptr = d;
+ unsigned char c;
+
+ /*
+ * Send an initial END character to flush out any
+ * data that may have accumulated in the receiver
+ * due to line noise.
+ */
+
+ *ptr++ = SLIP_END;
+
+ /*
+ * For each byte in the packet, send the appropriate
+ * character sequence, according to the SLIP protocol.
+ */
+
+ while (len-- > 0) {
+ switch(c = *s++) {
+ case SLIP_END:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_END;
+ break;
+ case SLIP_ESC:
+ *ptr++ = SLIP_ESC;
+ *ptr++ = SLIP_ESC_ESC;
+ break;
+ default:
+ *ptr++ = c;
+ break;
+ }
+ }
+ *ptr++ = SLIP_END;
+ return (ptr - d);
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index d8cd43c2f555..e36e8213671b 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -15,6 +15,7 @@
#include "user.h"
#include "net_user.h"
#include "slip.h"
+#include "slip_proto.h"
#include "helper.h"
#include "os.h"
@@ -66,7 +67,7 @@ static void slip_pre_exec(void *arg)
if(data->stdin != -1) dup2(data->stdin, 0);
dup2(data->stdout, 1);
- close(data->close_me);
+ if(data->close_me != -1) close(data->close_me);
}
static int slip_tramp(char **argv, int fd)
@@ -156,7 +157,7 @@ static int slip_open(void *data)
}
sencap = 0;
if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
- printk("Failed to sett slip encapsulation - "
+ printk("Failed to set slip encapsulation - "
"errno = %d\n", errno);
return(-errno);
}
@@ -186,103 +187,48 @@ static void slip_close(int fd, void *data)
pri->slave = -1;
}
-/* SLIP protocol characters. */
-#define END 0300 /* indicates end of frame */
-#define ESC 0333 /* indicates byte stuffing */
-#define ESC_END 0334 /* ESC ESC_END means END 'data' */
-#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
-
-static int slip_unesc(struct slip_data *sl, unsigned char c)
-{
- int ret;
-
- switch(c){
- case END:
- sl->esc = 0;
- ret = sl->pos;
- sl->pos = 0;
- return(ret);
- case ESC:
- sl->esc = 1;
- return(0);
- case ESC_ESC:
- if(sl->esc){
- sl->esc = 0;
- c = ESC;
- }
- break;
- case ESC_END:
- if(sl->esc){
- sl->esc = 0;
- c = END;
- }
- break;
- }
- sl->buf[sl->pos++] = c;
- return(0);
-}
-
int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
{
int i, n, size, start;
- n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos);
+ if(pri->more>0) {
+ i = 0;
+ while(i < pri->more) {
+ size = slip_unesc(pri->ibuf[i++],
+ pri->ibuf, &pri->pos, &pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
+ pri->more=pri->more-i;
+ return(size);
+ }
+ }
+ pri->more=0;
+ }
+
+ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
if(n <= 0) return(n);
start = pri->pos;
for(i = 0; i < n; i++){
- size = slip_unesc(pri, pri->buf[start + i]);
+ size = slip_unesc(pri->ibuf[start + i],
+ pri->ibuf, &pri->pos, &pri->esc);
if(size){
- memcpy(buf, pri->buf, size);
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
+ pri->more=n-(i+1);
return(size);
}
}
return(0);
}
-static int slip_esc(unsigned char *s, unsigned char *d, int len)
-{
- unsigned char *ptr = d;
- unsigned char c;
-
- /*
- * Send an initial END character to flush out any
- * data that may have accumulated in the receiver
- * due to line noise.
- */
-
- *ptr++ = END;
-
- /*
- * For each byte in the packet, send the appropriate
- * character sequence, according to the SLIP protocol.
- */
-
- while (len-- > 0) {
- switch(c = *s++) {
- case END:
- *ptr++ = ESC;
- *ptr++ = ESC_END;
- break;
- case ESC:
- *ptr++ = ESC;
- *ptr++ = ESC_ESC;
- break;
- default:
- *ptr++ = c;
- break;
- }
- }
- *ptr++ = END;
- return (ptr - d);
-}
-
int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
{
int actual, n;
- actual = slip_esc(buf, pri->buf, len);
- n = net_write(fd, pri->buf, actual);
+ actual = slip_esc(buf, pri->obuf, len);
+ n = net_write(fd, pri->obuf, actual);
if(n < 0) return(n);
else return(len);
}
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
new file mode 100644
index 000000000000..04e407d1e44a
--- /dev/null
+++ b/arch/um/drivers/slirp.h
@@ -0,0 +1,51 @@
+#ifndef __UM_SLIRP_H
+#define __UM_SLIRP_H
+
+#define BUF_SIZE 1500
+ /* two bytes each for a (pathological) max packet of escaped chars + *
+ * terminating END char + initial END char */
+#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
+
+#define SLIRP_MAX_ARGS 100
+/*
+ * XXX this next definition is here because I don't understand why this
+ * initializer doesn't work in slirp_kern.c:
+ *
+ * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
+ *
+ * or why I can't typecast like this:
+ *
+ * argv : (char* [SLIRP_MAX_ARGS])(init->argv),
+ */
+struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
+
+struct slirp_data {
+ void *dev;
+ struct arg_list_dummy_wrapper argw;
+ int pid;
+ int slave;
+ char ibuf[ENC_BUF_SIZE];
+ char obuf[ENC_BUF_SIZE];
+ int more; /* more data: do not read fd until ibuf has been drained */
+ int pos;
+ int esc;
+};
+
+extern struct net_user_info slirp_user_info;
+
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
+extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
new file mode 100644
index 000000000000..1a459dd94d76
--- /dev/null
+++ b/arch/um/drivers/slirp_kern.c
@@ -0,0 +1,132 @@
+#include "linux/kernel.h"
+#include "linux/stddef.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/if_arp.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "kern.h"
+#include "slirp.h"
+
+struct slirp_init {
+ struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
+};
+
+void slirp_init(struct net_device *dev, void *data)
+{
+ struct uml_net_private *private;
+ struct slirp_data *spri;
+ struct slirp_init *init = data;
+ int i;
+
+ private = dev->priv;
+ spri = (struct slirp_data *) private->user;
+ *spri = ((struct slirp_data)
+ { argw : init->argw,
+ pid : -1,
+ slave : -1,
+ ibuf : { '\0' },
+ obuf : { '\0' },
+ pos : 0,
+ esc : 0,
+ dev : dev });
+
+ dev->init = NULL;
+ dev->hard_header_len = 0;
+ dev->addr_len = 4;
+ dev->type = ARPHRD_ETHER;
+ dev->tx_queue_len = 256;
+ dev->flags = IFF_NOARP;
+ printk("SLIRP backend - command line:");
+ for(i=0;spri->argw.argv[i]!=NULL;i++) {
+ printk(" '%s'",spri->argw.argv[i]);
+ }
+ printk("\n");
+}
+
+static unsigned short slirp_protocol(struct sk_buff *skbuff)
+{
+ return(htons(ETH_P_IP));
+}
+
+static int slirp_read(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
+ (struct slirp_data *) &lp->user));
+}
+
+static int slirp_write(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ return(slirp_user_write(fd, (*skb)->data, (*skb)->len,
+ (struct slirp_data *) &lp->user));
+}
+
+struct net_kern_info slirp_kern_info = {
+ init: slirp_init,
+ protocol: slirp_protocol,
+ read: slirp_read,
+ write: slirp_write,
+};
+
+static int slirp_setup(char *str, char **mac_out, void *data)
+{
+ struct slirp_init *init = data;
+ int i=0;
+
+ *init = ((struct slirp_init)
+ { argw : { { "slirp", NULL } } });
+
+ str = split_if_spec(str, mac_out, NULL);
+
+ if(str == NULL) { /* no command line given after MAC addr */
+ return(1);
+ }
+
+ do {
+ if(i>=SLIRP_MAX_ARGS-1) {
+ printk("slirp_setup: truncating slirp arguments\n");
+ break;
+ }
+ init->argw.argv[i++] = str;
+ while(*str && *str!=',') {
+ if(*str=='_') *str=' ';
+ str++;
+ }
+ if(*str!=',')
+ break;
+ *str++='\0';
+ } while(1);
+ init->argw.argv[i]=NULL;
+ return(1);
+}
+
+static struct transport slirp_transport = {
+ list : LIST_HEAD_INIT(slirp_transport.list),
+ name : "slirp",
+ setup : slirp_setup,
+ user : &slirp_user_info,
+ kern : &slirp_kern_info,
+ private_size : sizeof(struct slirp_data),
+ setup_size : sizeof(struct slirp_init),
+};
+
+static int register_slirp(void)
+{
+ register_transport(&slirp_transport);
+ return(1);
+}
+
+__initcall(register_slirp);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
new file mode 100644
index 000000000000..bba76df0f33d
--- /dev/null
+++ b/arch/um/drivers/slirp_user.c
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "net_user.h"
+#include "slirp.h"
+#include "slip_proto.h"
+#include "helper.h"
+#include "os.h"
+
+void slirp_user_init(void *data, void *dev)
+{
+ struct slirp_data *pri = data;
+
+ pri->dev = dev;
+}
+
+struct slirp_pre_exec_data {
+ int stdin;
+ int stdout;
+};
+
+static void slirp_pre_exec(void *arg)
+{
+ struct slirp_pre_exec_data *data = arg;
+
+ if(data->stdin != -1) dup2(data->stdin, 0);
+ if(data->stdout != -1) dup2(data->stdout, 1);
+}
+
+static int slirp_tramp(char **argv, int fd)
+{
+ struct slirp_pre_exec_data pe_data;
+ int pid;
+
+ pe_data.stdin = fd;
+ pe_data.stdout = fd;
+ pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
+
+ return(pid);
+}
+
+static int slirp_datachan(int *mfd, int *sfd)
+{
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err){
+ printk("slirp_datachan: Failed to open pipe, errno = %d\n",
+ -err);
+ return(err);
+ }
+
+ *mfd = fds[0];
+ *sfd = fds[1];
+ return(0);
+}
+
+static int slirp_open(void *data)
+{
+ struct slirp_data *pri = data;
+ int sfd, mfd, pid, err;
+
+ err = slirp_datachan(&mfd, &sfd);
+ if(err)
+ return(err);
+
+ pid = slirp_tramp(pri->argw.argv, sfd);
+
+ if(pid < 0){
+ printk("slirp_tramp failed - errno = %d\n", pid);
+ os_close_file(sfd);
+ os_close_file(mfd);
+ return(pid);
+ }
+
+ pri->slave = sfd;
+ pri->pos = 0;
+ pri->esc = 0;
+
+ pri->pid = pid;
+
+ return(mfd);
+}
+
+static void slirp_close(int fd, void *data)
+{
+ struct slirp_data *pri = data;
+ int status,err;
+
+ close(fd);
+ close(pri->slave);
+
+ pri->slave = -1;
+
+ if(pri->pid<1) {
+ printk("slirp_close: no child process to shut down\n");
+ return;
+ }
+
+#if 0
+ if(kill(pri->pid, SIGHUP)<0) {
+ printk("slirp_close: sending hangup to %d failed (%d)\n",
+ pri->pid, errno);
+ }
+#endif
+
+ err = waitpid(pri->pid, &status, WNOHANG);
+ if(err<0) {
+ printk("slirp_close: waitpid returned %d\n", errno);
+ return;
+ }
+
+ if(err==0) {
+ printk("slirp_close: process %d has not exited\n");
+ return;
+ }
+
+ pri->pid = -1;
+}
+
+int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
+{
+ int i, n, size, start;
+
+ if(pri->more>0) {
+ i = 0;
+ while(i < pri->more) {
+ size = slip_unesc(pri->ibuf[i++],
+ pri->ibuf,&pri->pos,&pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
+ pri->more=pri->more-i;
+ return(size);
+ }
+ }
+ pri->more=0;
+ }
+
+ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
+ if(n <= 0) return(n);
+
+ start = pri->pos;
+ for(i = 0; i < n; i++){
+ size = slip_unesc(pri->ibuf[start + i],
+ pri->ibuf,&pri->pos,&pri->esc);
+ if(size){
+ memcpy(buf, pri->ibuf, size);
+ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
+ pri->more=n-(i+1);
+ return(size);
+ }
+ }
+ return(0);
+}
+
+int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
+{
+ int actual, n;
+
+ actual = slip_esc(buf, pri->obuf, len);
+ n = net_write(fd, pri->obuf, actual);
+ if(n < 0) return(n);
+ else return(len);
+}
+
+static int slirp_set_mtu(int mtu, void *data)
+{
+ return(mtu);
+}
+
+struct net_user_info slirp_user_info = {
+ init: slirp_user_init,
+ open: slirp_open,
+ close: slirp_close,
+ remove: NULL,
+ set_mtu: slirp_set_mtu,
+ add_address: NULL,
+ delete_address: NULL,
+ max_packet: BUF_SIZE
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index c0cd826d9d8b..4f0b772a4f88 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -20,6 +20,7 @@
#include "kern.h"
#include "init.h"
#include "irq_user.h"
+#include "mconsole_kern.h"
#include "2_5compat.h"
static int ssl_version = 1;
@@ -47,6 +48,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
+static int ssl_config(char *str);
+static int ssl_get_config(char *dev, char *str, int size, char **error_out);
+static int ssl_remove(char *str);
+
static struct line_driver driver = {
name : "UML serial line",
devfs_name : "tts/%d",
@@ -60,6 +65,12 @@ static struct line_driver driver = {
write_irq_name : "ssl-write",
symlink_from : "serial",
symlink_to : "tts",
+ mc : {
+ name : "ssl",
+ config : ssl_config,
+ get_config : ssl_get_config,
+ remove : ssl_remove,
+ },
};
/* The array is initialized by line_init, which is an initcall. The
@@ -70,6 +81,25 @@ static struct line serial_lines[NR_PORTS] =
static struct lines lines = LINES_INIT(NR_PORTS);
+static int ssl_config(char *str)
+{
+ return(line_config(serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+}
+
+static int ssl_get_config(char *dev, char *str, int size, char **error_out)
+{
+ return(line_get_config(dev, serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]),
+ str, size, error_out));
+}
+
+static int ssl_remove(char *str)
+{
+ return(line_remove(serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+}
+
int ssl_open(struct tty_struct *tty, struct file *filp)
{
return(line_open(serial_lines, tty, &opts));
@@ -83,12 +113,12 @@ static void ssl_close(struct tty_struct *tty, struct file * filp)
static int ssl_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
- return(line_write(serial_lines, tty, buf, count));
+ return(line_write(serial_lines, tty, from_user, buf, count));
}
static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
{
- line_write(serial_lines, tty, &ch, sizeof(ch));
+ line_write(serial_lines, tty, 0, &ch, sizeof(ch));
}
static void ssl_flush_chars(struct tty_struct *tty)
@@ -207,7 +237,7 @@ __initcall(ssl_init);
static int ssl_chan_setup(char *str)
{
line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
- str);
+ str, 1);
return(1);
}
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 4803c3e071b0..3844a7188508 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -27,6 +27,7 @@
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
+#include "mconsole_kern.h"
#include "init.h"
#include "2_5compat.h"
@@ -41,6 +42,7 @@ static struct tty_driver console_driver;
static int console_refcount = 0;
static struct chan_ops init_console_ops = {
+ type: "you shouldn't see this",
init : NULL,
open : NULL,
close : NULL,
@@ -78,6 +80,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
+static int con_config(char *str);
+static int con_get_config(char *dev, char *str, int size, char **error_out);
+static int con_remove(char *str);
+
static struct line_driver driver = {
name : "UML console",
devfs_name : "vc/%d",
@@ -91,6 +97,12 @@ static struct line_driver driver = {
write_irq_name : "console-write",
symlink_from : "ttys",
symlink_to : "vc",
+ mc : {
+ name : "con",
+ config : con_config,
+ get_config : con_get_config,
+ remove : con_remove,
+ },
};
static struct lines console_lines = LINES_INIT(MAX_TTYS);
@@ -102,6 +114,22 @@ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
[ 1 ... MAX_TTYS - 1 ] =
LINE_INIT(CONFIG_CON_CHAN, &driver) };
+static int con_config(char *str)
+{
+ return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
+}
+
+static int con_get_config(char *dev, char *str, int size, char **error_out)
+{
+ return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
+ size, error_out));
+}
+
+static int con_remove(char *str)
+{
+ return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
+}
+
static int open_console(struct tty_struct *tty)
{
return(line_open(vts, tty, &opts));
@@ -120,7 +148,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
static int con_write(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count)
{
- return(line_write(vts, tty, buf, count));
+ return(line_write(vts, tty, from_user, buf, count));
}
static void set_termios(struct tty_struct *tty, struct termios * old)
@@ -195,7 +223,7 @@ void stdio_console_init(void)
static int console_chan_setup(char *str)
{
- line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
+ line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1);
return(1);
}
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index 75b4b93102b0..438e72268ef6 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -30,14 +30,15 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts)
}
str++;
- if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+ if((data = um_kmalloc(sizeof(*data))) == NULL)
+ return(NULL);
*data = ((struct tty_chan) { dev : str,
raw : opts->raw });
return(data);
}
-int tty_open(int input, int output, int primary, void *d)
+int tty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct tty_chan *data = d;
int fd;
@@ -48,6 +49,8 @@ int tty_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
+
+ *dev_out = data->dev;
return(fd);
}
@@ -59,6 +62,7 @@ int tty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops tty_ops = {
+ type: "tty",
init: tty_chan_init,
open: tty_open,
close: generic_close,
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 93228f048940..2d9dfba302e8 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -218,7 +218,7 @@ static int ubd_setup_common(char *str, int *index_out)
return(0);
}
major = simple_strtoul(str, &end, 0);
- if(*end != '\0'){
+ if((*end != '\0') || (end == str)){
printk(KERN_ERR
"ubd_setup : didn't parse major number\n");
return(1);
@@ -520,7 +520,10 @@ static int ubd_add(int n)
struct ubd *dev = &ubd_dev[n];
int err;
- if (!dev->file || dev->is_dir)
+ if(dev->is_dir)
+ return(-EISDIR);
+
+ if (!dev->file)
return(-ENODEV);
if (ubd_open_dev(dev))
@@ -574,6 +577,44 @@ static int ubd_config(char *str)
return(err);
}
+static int ubd_get_config(char *dev, char *str, int size, char **error_out)
+{
+ struct ubd *ubd;
+ char *end;
+ int major, n = 0;
+
+ major = simple_strtoul(dev, &end, 0);
+ if((*end != '\0') || (end == dev)){
+ *error_out = "ubd_get_config : didn't parse major number";
+ return(-1);
+ }
+
+ if((major >= MAX_DEV) || (major < 0)){
+ *error_out = "ubd_get_config : major number out of range";
+ return(-1);
+ }
+
+ ubd = &ubd_dev[major];
+ spin_lock(&ubd_lock);
+
+ if(ubd->file == NULL){
+ CONFIG_CHUNK(str, size, n, "", 1);
+ goto out;
+ }
+
+ CONFIG_CHUNK(str, size, n, ubd->file, 0);
+
+ if(ubd->cow.file != NULL){
+ CONFIG_CHUNK(str, size, n, ",", 0);
+ CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
+ }
+ else CONFIG_CHUNK(str, size, n, "", 1);
+
+ out:
+ spin_unlock(&ubd_lock);
+ return(n);
+}
+
static int ubd_remove(char *str)
{
struct ubd *dev;
@@ -583,7 +624,7 @@ static int ubd_remove(char *str)
return(err); /* it should be a number 0-7/a-h */
n = *str - '0';
- if(n > MAX_DEV)
+ if(n >= MAX_DEV)
return(err);
dev = &ubd_dev[n];
@@ -620,6 +661,7 @@ static int ubd_remove(char *str)
static struct mc_device ubd_mc = {
.name = "ubd",
.config = ubd_config,
+ .get_config = ubd_get_config,
.remove = ubd_remove,
};
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index 8a4b6f52888c..93b6f3e90c22 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -473,6 +473,8 @@ void do_io(struct io_thread_req *req)
&req->sector_mask) == bit))
end++;
+ if(end != nsectors)
+ printk("end != nsectors\n");
off = req->offset + req->offsets[bit] +
start * req->sectorsize;
len = (end - start) * req->sectorsize;
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index e7b4ab83c8f7..7e351c8012ad 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -83,7 +83,7 @@ __uml_setup("xterm=", xterm_setup,
" are 'xterm=gnome-terminal,-t,-x'.\n\n"
);
-int xterm_open(int input, int output, int primary, void *d)
+int xterm_open(int input, int output, int primary, void *d, char **dev_out)
{
struct xterm_chan *data = d;
unsigned long stack;
@@ -93,6 +93,9 @@ int xterm_open(int input, int output, int primary, void *d)
"/usr/lib/uml/port-helper", "-uml-socket",
file, NULL };
+ if(access(argv[4], X_OK))
+ argv[4] = "port-helper";
+
fd = mkstemp(file);
if(fd < 0){
printk("xterm_open : mkstemp failed, errno = %d\n", errno);
@@ -141,6 +144,7 @@ int xterm_open(int input, int output, int primary, void *d)
if(data->raw) raw(new, 0);
data->pid = pid;
+ *dev_out = NULL;
return(new);
}
@@ -168,6 +172,7 @@ int xterm_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops xterm_ops = {
+ type: "xterm",
init: xterm_init,
open: xterm_open,
close: xterm_close,
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index 28b2835bcb7c..c2308894a81e 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -22,11 +22,13 @@ struct xterm_wait {
static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
{
struct xterm_wait *xterm = data;
+ int fd;
- xterm->new_fd = os_rcv_fd(xterm->fd, &xterm->pid);
- if(xterm->new_fd == -EAGAIN)
+ fd = os_rcv_fd(xterm->fd, &xterm->pid);
+ if(fd == -EAGAIN)
return;
+ xterm->new_fd = fd;
up(&xterm->sem);
}
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
index 8c2bb85c9edf..d2cd02a03c61 100644
--- a/arch/um/include/chan_kern.h
+++ b/arch/um/include/chan_kern.h
@@ -12,6 +12,7 @@
struct chan {
struct list_head list;
+ char *dev;
unsigned int primary:1;
unsigned int input:1;
unsigned int output:1;
@@ -38,6 +39,8 @@ extern int chan_window_size(struct list_head *chans,
unsigned short *rows_out,
unsigned short *cols_out);
extern int chan_out_fd(struct list_head *chans);
+extern int chan_config_string(struct list_head *chans, char *str, int size,
+ char **error_out);
#endif
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index 639ca8d6121a..9414c1a44c6d 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -19,8 +19,9 @@ struct chan_opts {
enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
struct chan_ops {
+ char *type;
void *(*init)(char *, int, struct chan_opts *);
- int (*open)(int, int, int, void *);
+ int (*open)(int, int, int, void *, char **);
void (*close)(int, void *);
int (*read)(int, char *, void *);
int (*write)(int, const char *, int, void *);
@@ -43,7 +44,6 @@ extern void generic_free(void *data);
extern void register_winch(int fd, void *device_data);
extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
-extern void setup_tracer_winch(void);
#define __channel_help(fn, prefix) \
__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h
new file mode 100644
index 000000000000..55548984bd85
--- /dev/null
+++ b/arch/um/include/choose-mode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __CHOOSE_MODE_H__
+#define __CHOOSE_MODE_H__
+
+#include "uml-config.h"
+
+#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
+#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
+
+#elif defined(CONFIG_MODE_SKAS)
+#define CHOOSE_MODE(tt, skas) (skas)
+
+#elif defined(CONFIG_MODE_TT)
+#define CHOOSE_MODE(tt, skas) (tt)
+#endif
+
+#define CHOOSE_MODE_PROC(tt, skas, args...) \
+ CHOOSE_MODE(tt(args), skas(args))
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/frame.h b/arch/um/include/frame.h
index 9df95a5f00a1..b4e12946f54f 100644
--- a/arch/um/include/frame.h
+++ b/arch/um/include/frame.h
@@ -8,34 +8,34 @@
#include "sysdep/frame.h"
-struct sc_frame {
+struct frame_common {
void *data;
int len;
int sig_index;
- int sc_index;
int sr_index;
int sr_relative;
int sp_index;
+};
+
+struct sc_frame {
+ struct frame_common common;
+ int sc_index;
struct arch_frame_data arch;
};
extern struct sc_frame signal_frame_sc;
+extern struct sc_frame signal_frame_sc_sr;
+
struct si_frame {
- void *data;
- int len;
- int sig_index;
+ struct frame_common common;
int sip_index;
int si_index;
- int sr_index;
- int sr_relative;
- int sp_index;
};
extern struct si_frame signal_frame_si;
extern void capture_signal_stack(void);
-extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
#endif
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h
index 09eae635a15e..3e3aed19f54c 100644
--- a/arch/um/include/kern.h
+++ b/arch/um/include/kern.h
@@ -25,7 +25,6 @@ extern void *sbrk(int increment);
extern void *malloc(int size);
extern void perror(char *err);
extern int kill(int pid, int sig);
-extern int getpid(void);
extern int getuid(void);
extern int pause(void);
extern int write(int, const void *, int);
@@ -34,6 +33,7 @@ extern int close(int);
extern int read(unsigned int, char *, int);
extern int pipe(int *);
extern int sched_yield(void);
+extern int ptrace(int op, int pid, long addr, long data);
#endif
/*
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 076b94d75765..8bef1a8a6153 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -15,23 +15,26 @@ extern char *gdb_init;
extern int kmalloc_ok;
extern int timer_irq_inited;
extern int jail;
+extern int nsyscalls;
+
extern struct task_struct *idle_threads[NR_CPUS];
-#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
-#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
+#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
+#define UML_ROUND_UP(addr) \
+ UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
extern unsigned long stack_sp(unsigned long page);
extern int kernel_thread_proc(void *data);
extern void syscall_segv(int sig);
extern int current_pid(void);
-extern void set_init_pid(int pid);
extern unsigned long alloc_stack(int order, int atomic);
extern int do_signal(int error);
extern int is_stack_fault(unsigned long sp);
extern unsigned long segv(unsigned long address, unsigned long ip,
- int is_write, int is_user, void *sc_ptr);
-extern int set_user_mode(void *task);
+ int is_write, int is_user, void *sc);
+extern int handle_page_fault(unsigned long address, unsigned long ip,
+ int is_write, int is_user, int *code_out);
extern void syscall_ready(void);
extern void set_tracing(void *t, int tracing);
extern int is_tracing(void *task);
@@ -40,7 +43,6 @@ extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
extern int page_size(void);
extern int page_mask(void);
extern int need_finish_fork(void);
-extern int do_proc_op(void *t, int proc_id);
extern void free_stack(unsigned long stack, int order);
extern void add_input_request(int op, void (*proc)(int), void *arg);
extern int sys_execve(char *file, char **argv, char **env);
@@ -57,7 +59,6 @@ extern int next_trap_index(int max);
extern void default_idle(void);
extern void finish_fork(void);
extern void paging_init(void);
-extern unsigned long um_virt_to_phys(void *t, unsigned long addr);
extern void init_flush_vm(void);
extern void *syscall_sp(void *t);
extern void syscall_trace(void);
@@ -68,35 +69,28 @@ extern int external_pid(void *t);
extern int pid_to_processor_id(int pid);
extern void boot_timer_handler(int sig);
extern void interrupt_end(void);
-extern void tracing_reboot(void);
-extern void tracing_halt(void);
-extern void tracing_cb(void (*proc)(void *), void *arg);
+extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int debugger_signal(int status, int pid);
extern void debugger_parent_signal(int status, int pid);
extern void child_signal(int pid, int status);
extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
extern int init_parent_proxy(int pid);
+extern int singlestepping(void *t);
extern void check_stack_overflow(void *ptr);
extern void relay_signal(int sig, struct uml_pt_regs *regs);
-extern int singlestepping(void *t);
-extern void clear_singlestep(void *t);
extern void not_implemented(void);
extern int user_context(unsigned long sp);
extern void timer_irq(struct uml_pt_regs *regs);
extern void unprotect_stack(unsigned long stack);
extern void do_uml_exitcalls(void);
extern int attach_debugger(int idle_pid, int pid, int stop);
-extern void *round_up(unsigned long addr);
-extern void *round_down(unsigned long addr);
extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
extern int config_gdb(char *str);
extern int remove_gdb(void);
extern char *uml_strdup(char *string);
extern void unprotect_kernel_mem(void);
extern void protect_kernel_mem(void);
-extern unsigned long get_kmem_end(void);
extern void set_kmem_end(unsigned long);
-extern void set_task_sizes(int arg);
extern void uml_cleanup(void);
extern int pid_to_processor_id(int pid);
extern void set_current(void *t);
@@ -107,7 +101,6 @@ extern void *get_init_task(void);
extern int clear_user_proc(void *buf, int size);
extern int copy_to_user_proc(void *to, void *from, int size);
extern int copy_from_user_proc(void *to, void *from, int size);
-extern void set_thread_sc(void *sc);
extern void bus_handler(int sig, struct uml_pt_regs *regs);
extern long execute_syscall(void *r);
extern int smp_sigio_handler(void);
@@ -116,7 +109,6 @@ extern struct task_struct *get_task(int pid, int require);
extern void machine_halt(void);
extern int is_syscall(unsigned long addr);
extern void arch_switch(void);
-extern int is_valid_pid(int pid);
extern void free_irq(unsigned int, void *);
extern int um_in_interrupt(void);
extern int cpu(void);
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 4d45c270a80e..8bad9c56c66e 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -11,6 +11,7 @@
#include "linux/tty.h"
#include "asm/semaphore.h"
#include "chan_user.h"
+#include "mconsole_kern.h"
struct line_driver {
char *name;
@@ -25,6 +26,7 @@ struct line_driver {
char *write_irq_name;
char *symlink_from;
char *symlink_to;
+ struct mc_device mc;
};
struct line {
@@ -70,8 +72,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
extern void line_close(struct line *lines, struct tty_struct *tty);
extern int line_open(struct line *lines, struct tty_struct *tty,
struct chan_opts *opts);
-extern void line_setup(struct line *lines, int num, char *init);
-extern int line_write(struct line *line, struct tty_struct *tty,
+extern int line_setup(struct line *lines, int num, char *init,
+ int all_allowed);
+extern int line_write(struct line *line, struct tty_struct *tty, int from_user,
const char *buf, int len);
extern int line_write_room(struct tty_struct *tty);
extern char *add_xterm_umid(char *base);
@@ -84,6 +87,10 @@ extern void line_register_devfs(struct lines *set,
int nlines);
extern void lines_init(struct line *lines, int nlines);
extern void close_lines(struct line *lines, int nlines);
+extern int line_config(struct line *lines, int num, char *str);
+extern int line_remove(struct line *lines, int num, char *str);
+extern int line_get_config(char *dev, struct line *lines, int num, char *str,
+ int size, char **error_out);
#endif
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
index 03c6d1734a28..61c274fcee5d 100644
--- a/arch/um/include/mconsole_kern.h
+++ b/arch/um/include/mconsole_kern.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -19,9 +19,23 @@ struct mc_device {
struct list_head list;
char *name;
int (*config)(char *);
+ int (*get_config)(char *, char *, int, char **);
int (*remove)(char *);
};
+#define CONFIG_CHUNK(str, size, current, chunk, end) \
+do { \
+ current += strlen(chunk); \
+ if(current >= size) \
+ str = NULL; \
+ if(str != NULL){ \
+ strcpy(str, chunk); \
+ str += strlen(chunk); \
+ } \
+ if(end) \
+ current++; \
+} while(0)
+
#ifdef CONFIG_MCONSOLE
extern void mconsole_register_dev(struct mc_device *new);
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index e7835b541196..bad6b30b8f7d 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -13,6 +13,7 @@ struct vm_reserved {
};
extern void set_usable_vm(unsigned long start, unsigned long end);
+extern void set_kmem_end(unsigned long new);
#endif
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
index 4a3e68d56a5a..d80ac354bf28 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -54,11 +54,6 @@ extern int create_mem_file(unsigned long len);
extern void setup_range(int fd, char *driver, unsigned long start,
unsigned long pfn, unsigned long total, int need_vm,
struct mem_region *region, void *reserved);
-extern void map(unsigned long virt, unsigned long p, unsigned long len,
- int r, int w, int x);
-extern int unmap(void *addr, int len);
-extern int protect(unsigned long addr, unsigned long len, int r, int w,
- int x, int must_succeed);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
extern int init_maps(struct mem_region *region);
@@ -68,10 +63,15 @@ extern unsigned long get_vm(unsigned long len);
extern void setup_physmem(unsigned long start, unsigned long usable,
unsigned long len);
extern int setup_region(struct mem_region *region, void *entry);
-extern void add_iomem(char *name, int fd, int size);
+extern void add_iomem(char *name, int fd, unsigned long size);
extern struct mem_region *phys_region(unsigned long phys);
extern unsigned long phys_offset(unsigned long phys);
extern void unmap_physmem(void);
+extern int map_memory(unsigned long virt, unsigned long phys,
+ unsigned long len, int r, int w, int x);
+extern int protect_memory(unsigned long addr, unsigned long len,
+ int r, int w, int x, int must_succeed);
+extern unsigned long get_kmem_end(void);
#endif
diff --git a/arch/um/include/mode.h b/arch/um/include/mode.h
new file mode 100644
index 000000000000..ba7f6ff04121
--- /dev/null
+++ b/arch/um/include/mode.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_H__
+#define __MODE_H__
+
+#include "uml-config.h"
+
+#ifdef CONFIG_MODE_TT
+#include "../kernel/tt/include/mode.h"
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+#include "../kernel/skas/include/mode.h"
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h
new file mode 100644
index 000000000000..562174bf48a0
--- /dev/null
+++ b/arch/um/include/mode_kern.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_KERN_H__
+#define __MODE_KERN_H__
+
+#include "linux/config.h"
+
+#ifdef CONFIG_MODE_TT
+#include "../kernel/tt/include/mode_kern.h"
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+#include "../kernel/skas/include/mode_kern.h"
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index 22d43acb78f1..de793e9bf438 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_NET_KERN_H
#define __UM_NET_KERN_H
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
index 01867cae92e2..36807b796e9f 100644
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_NET_USER_H__
#define __UM_NET_USER_H__
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 1c1e3a8b5eb6..524a60875d7b 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -103,10 +103,16 @@ extern int os_write_file(int fd, char *buf, int count);
extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid);
extern void os_stop_process(int pid);
-extern void os_kill_process(int pid);
+extern void os_kill_process(int pid, int reap_child);
extern void os_usr1_process(int pid);
extern int os_getpid(void);
+extern int os_map_memory(void *virt, int fd, unsigned long off,
+ unsigned long len, int r, int w, int x);
+extern int os_protect_memory(void *addr, unsigned long len,
+ int r, int w, int x);
+extern int os_unmap_memory(void *addr, int len);
+
#endif
/*
diff --git a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h
index 1d2b195bc5f8..59816ca7a8df 100644
--- a/arch/um/include/sigcontext.h
+++ b/arch/um/include/sigcontext.h
@@ -9,8 +9,6 @@
#include "sysdep/sigcontext.h"
extern int sc_size(void *data);
-extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data);
-extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data);
extern void sc_to_sc(void *to_ptr, void *from_ptr);
#endif
diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h
index e430752cb7ec..bc7be6293702 100644
--- a/arch/um/include/syscall_user.h
+++ b/arch/um/include/syscall_user.h
@@ -1,16 +1,13 @@
/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
-#ifndef __SYSCALL_USER_H__
-#define __SYSCALL_USER_H__
+#ifndef __SYSCALL_USER_H
+#define __SYSCALL_USER_H
-#include <asm/sigcontext.h>
-
-extern void syscall_handler(int sig, struct uml_pt_regs *regs);
-extern void exit_kernel(int pid, void *task);
-extern int do_syscall(void *task, int pid);
+extern int record_syscall_start(int syscall);
+extern void record_syscall_end(int index, int result);
#endif
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
new file mode 100644
index 000000000000..c77e434d61a9
--- /dev/null
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -0,0 +1,217 @@
+/*
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_SYSDEP_CHECKSUM_H
+#define __UM_SYSDEP_CHECKSUM_H
+
+#include "linux/string.h"
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len,
+ unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
+ int sum, int *err_ptr);
+unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
+ int sum, int *err_ptr);
+
+/*
+ * Note: when you get a NULL pointer exception here this means someone
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
+ * verify_area().
+ */
+
+static __inline__
+unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
+ int len, int sum)
+{
+ memcpy(dst, src, len);
+ return(csum_partial(dst, len, sum));
+}
+
+static __inline__
+unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_from(src, dst, len, sum, err_ptr);
+}
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message
+ * will be printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
+ */
+
+#define csum_partial_copy_fromuser csum_partial_copy_from_user
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ * Arnt Gulbrandsen.
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+ unsigned int ihl)
+{
+ unsigned int sum;
+
+ __asm__ __volatile__(
+ "movl (%1), %0 ;\n"
+ "subl $4, %2 ;\n"
+ "jbe 2f ;\n"
+ "addl 4(%1), %0 ;\n"
+ "adcl 8(%1), %0 ;\n"
+ "adcl 12(%1), %0 ;\n"
+"1: adcl 16(%1), %0 ;\n"
+ "lea 4(%1), %1 ;\n"
+ "decl %2 ;\n"
+ "jne 1b ;\n"
+ "adcl $0, %0 ;\n"
+ "movl %0, %2 ;\n"
+ "shrl $16, %0 ;\n"
+ "addw %w2, %w0 ;\n"
+ "adcl $0, %0 ;\n"
+ "notl %0 ;\n"
+"2: ;\n"
+ /* Since the input registers which are loaded with iph and ipl
+ are modified, we must also specify them as outputs, or gcc
+ will assume they contain their original values. */
+ : "=r" (sum), "=r" (iph), "=r" (ihl)
+ : "1" (iph), "2" (ihl));
+ return(sum);
+}
+
+/*
+ * Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+ __asm__(
+ "addl %1, %0 ;\n"
+ "adcl $0xffff, %0 ;\n"
+ : "=r" (sum)
+ : "r" (sum << 16), "0" (sum & 0xffff0000)
+ );
+ return (~sum) >> 16;
+}
+
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__(
+ "addl %1, %0 ;\n"
+ "adcl %2, %0 ;\n"
+ "adcl %3, %0 ;\n"
+ "adcl $0, %0 ;\n"
+ : "=r" (sum)
+ : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u32 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__(
+ "addl 0(%1), %0 ;\n"
+ "adcl 4(%1), %0 ;\n"
+ "adcl 8(%1), %0 ;\n"
+ "adcl 12(%1), %0 ;\n"
+ "adcl 0(%2), %0 ;\n"
+ "adcl 4(%2), %0 ;\n"
+ "adcl 8(%2), %0 ;\n"
+ "adcl 12(%2), %0 ;\n"
+ "adcl %3, %0 ;\n"
+ "adcl %4, %0 ;\n"
+ "adcl $0, %0 ;\n"
+ : "=&r" (sum)
+ : "r" (saddr), "r" (daddr),
+ "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
+
+ return csum_fold(sum);
+}
+
+/*
+ * Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user(const char *src,
+ char *dst, int len,
+ int sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_WRITE, dst, len))
+ return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
+
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return -1; /* invalid checksum */
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/sysdep-i386/frame_kern.h b/arch/um/include/sysdep-i386/frame_kern.h
index ec234c6e15c1..f469b8c6ea23 100644
--- a/arch/um/include/sysdep-i386/frame_kern.h
+++ b/arch/um/include/sysdep-i386/frame_kern.h
@@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp)
{
unsigned long sc;
- sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4;
+ sc = sp - signal_frame_si.common.sp_index +
+ signal_frame_si.common.len - 4;
return((void *) sc);
}
@@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp)
{
unsigned long mask;
- mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8;
+ mask = sp - signal_frame_sc.common.sp_index +
+ signal_frame_sc.common.len - 8;
return((void *) mask);
}
@@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp)
{
unsigned long mask;
- mask = sp - signal_frame_si.sp_index + signal_frame_si.len +
+ mask = sp - signal_frame_si.common.sp_index +
+ signal_frame_si.common.len +
sc_size(&signal_frame_sc.arch) - 4;
return((void *) mask);
}
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
index 46aa12342153..e658d491bc5b 100644
--- a/arch/um/include/sysdep-i386/ptrace.h
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -1,44 +1,78 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SYSDEP_I386_PTRACE_H
#define __SYSDEP_I386_PTRACE_H
-#include "sysdep/sc.h"
+#include "uml-config.h"
+#include "ptrace-tt.h"
+#include "ptrace-skas.h"
+#include "choose-mode.h"
struct uml_pt_regs {
unsigned long args[6];
long syscall;
int is_user;
- void *sc;
+ union {
+#ifdef CONFIG_MODE_TT
+ void *tt;
+#endif
+#ifdef CONFIG_MODE_SKAS
+ struct {
+ unsigned long regs[HOST_FRAME_SIZE];
+ unsigned long fp[HOST_FP_SIZE];
+ unsigned long xfp[HOST_XFP_SIZE];
+ unsigned long fault_addr;
+ unsigned long fault_type;
+ unsigned long trap_type;
+ } skas;
+#endif
+ } mode;
};
#define EMPTY_UML_PT_REGS { \
syscall : -1, \
args : { [0 ... 5] = 0 }, \
- is_user : 0, \
- sc : NULL }
-
-#define UPT_IP(regs) SC_IP((regs)->sc)
-#define UPT_SP(regs) SC_SP((regs)->sc)
-#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc)
-#define UPT_EAX(regs) SC_EAX((regs)->sc)
-#define UPT_EBX(regs) SC_EBX((regs)->sc)
-#define UPT_ECX(regs) SC_ECX((regs)->sc)
-#define UPT_EDX(regs) SC_EDX((regs)->sc)
-#define UPT_ESI(regs) SC_ESI((regs)->sc)
-#define UPT_EDI(regs) SC_EDI((regs)->sc)
-#define UPT_EBP(regs) SC_EBP((regs)->sc)
-#define UPT_ORIG_EAX(regs) ((regs)->syscall)
-#define UPT_CS(regs) SC_CS((regs)->sc)
-#define UPT_SS(regs) SC_SS((regs)->sc)
-#define UPT_DS(regs) SC_DS((regs)->sc)
-#define UPT_ES(regs) SC_ES((regs)->sc)
-#define UPT_FS(regs) SC_FS((regs)->sc)
-#define UPT_GS(regs) SC_GS((regs)->sc)
-#define UPT_SC(regs) ((regs)->sc)
+ is_user : 0 }
+
+extern int mode_tt;
+
+#define UPT_IP(r) \
+ CHOOSE_MODE(SC_IP((r)->mode.tt), REGS_IP((r)->mode.skas.regs))
+#define UPT_SP(r) \
+ CHOOSE_MODE(SC_SP((r)->mode.tt), REGS_SP((r)->mode.skas.regs))
+#define UPT_EFLAGS(r) \
+ CHOOSE_MODE(SC_EFLAGS((r)->mode.tt), REGS_EFLAGS((r)->mode.skas.regs))
+#define UPT_EAX(r) \
+ CHOOSE_MODE(SC_EAX((r)->mode.tt), REGS_EAX((r)->mode.skas.regs))
+#define UPT_EBX(r) \
+ CHOOSE_MODE(SC_EBX((r)->mode.tt), REGS_EBX((r)->mode.skas.regs))
+#define UPT_ECX(r) \
+ CHOOSE_MODE(SC_ECX((r)->mode.tt), REGS_ECX((r)->mode.skas.regs))
+#define UPT_EDX(r) \
+ CHOOSE_MODE(SC_EDX((r)->mode.tt), REGS_EDX((r)->mode.skas.regs))
+#define UPT_ESI(r) \
+ CHOOSE_MODE(SC_ESI((r)->mode.tt), REGS_ESI((r)->mode.skas.regs))
+#define UPT_EDI(r) \
+ CHOOSE_MODE(SC_EDI((r)->mode.tt), REGS_EDI((r)->mode.skas.regs))
+#define UPT_EBP(r) \
+ CHOOSE_MODE(SC_EBP((r)->mode.tt), REGS_EBP((r)->mode.skas.regs))
+#define UPT_ORIG_EAX(r) ((r)->syscall)
+#define UPT_CS(r) \
+ CHOOSE_MODE(SC_CS((r)->mode.tt), REGS_CS((r)->mode.skas.regs))
+#define UPT_SS(r) \
+ CHOOSE_MODE(SC_SS((r)->mode.tt), REGS_SS((r)->mode.skas.regs))
+#define UPT_DS(r) \
+ CHOOSE_MODE(SC_DS((r)->mode.tt), REGS_DS((r)->mode.skas.regs))
+#define UPT_ES(r) \
+ CHOOSE_MODE(SC_ES((r)->mode.tt), REGS_ES((r)->mode.skas.regs))
+#define UPT_FS(r) \
+ CHOOSE_MODE(SC_FS((r)->mode.tt), REGS_FS((r)->mode.skas.regs))
+#define UPT_GS(r) \
+ CHOOSE_MODE(SC_GS((r)->mode.tt), REGS_GS((r)->mode.skas.regs))
+#define UPT_SC(r) ((r)->mode.tt)
#define UPT_REG(regs, reg) \
({ unsigned long val; \
@@ -94,12 +128,29 @@ struct uml_pt_regs {
} \
} while (0)
-#define UPT_SET_SYSCALL_RETURN(regs, res) \
- SC_SET_SYSCALL_RETURN((regs)->sc, (res))
-#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc)
-#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs)
-#define UPT_SYSCALL_NR(regs) ((regs)->syscall)
-#define UPT_SYSCALL_RET(regs) UPT_EAX(regs)
+#define UPT_SET_SYSCALL_RETURN(r, res) \
+ CHOOSE_MODE(SC_SET_SYSCALL_RETURN((r)->mode.tt, (res)), \
+ REGS_SET_SYSCALL_RETURN((r)->mode.skas.regs, (res)))
+
+#define UPT_RESTART_SYSCALL(r) \
+ CHOOSE_MODE(SC_RESTART_SYSCALL((r)->mode.tt), \
+ REGS_RESTART_SYSCALL((r)->mode.skas.regs))
+
+#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
+#define UPT_SYSCALL_NR(r) ((r)->syscall)
+#define UPT_SYSCALL_RET(r) UPT_EAX(r)
+
+#define UPT_SEGV_IS_FIXABLE(r) \
+ CHOOSE_MODE(SC_SEGV_IS_FIXABLE(r->mode.tt), \
+ REGS_SEGV_IS_FIXABLE(&r->mode.skas))
+
+#define UPT_FAULT_ADDR(r) \
+ CHOOSE_MODE(SC_FAULT_ADDR(r->mode.tt), \
+ REGS_FAULT_ADDR(&r->mode.skas))
+
+#define UPT_FAULT_WRITE(r) \
+ CHOOSE_MODE(SC_FAULT_WRITE(r->mode.tt), \
+ REGS_FAULT_WRITE(&r->mode.skas))
#endif
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
index f445f375c9a4..d52262e31499 100644
--- a/arch/um/include/sysdep-i386/sigcontext.h
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -6,13 +6,22 @@
#ifndef __SYS_SIGCONTEXT_I386_H
#define __SYS_SIGCONTEXT_I386_H
+#include "sc.h"
+
#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
-#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0)
+#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result)
#define SC_FAULT_ADDR(sc) SC_CR2(sc)
-#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2)
+#define SC_FAULT_TYPE(sc) SC_ERR(sc)
+
+#define FAULT_WRITE(err) (err & 2)
+#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
+
+#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
+
+#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
/* ptrace expects that, at the start of a system call, %eax contains
* -ENOSYS, so this makes it so.
@@ -20,10 +29,12 @@
#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
/* These are General Protection and Page Fault */
-#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14))
+#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14))
-/* XXX struct sigcontext needs declaring by now */
+#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
+#ifdef CONFIG_MODE_TT
+/* XXX struct sigcontext needs declaring by now */
static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
unsigned long syscall)
{
@@ -35,6 +46,20 @@ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
regs->args[4] = SC_EDI(sc);
regs->args[5] = SC_EBP(sc);
}
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+static inline void host_to_regs(struct uml_pt_regs *regs)
+{
+ regs->syscall = UPT_ORIG_EAX(regs);
+ regs->args[0] = UPT_EBX(regs);
+ regs->args[1] = UPT_ECX(regs);
+ regs->args[2] = UPT_EDX(regs);
+ regs->args[3] = UPT_ESI(regs);
+ regs->args[4] = UPT_EDI(regs);
+ regs->args[5] = UPT_EBP(regs);
+}
+#endif
extern unsigned long *sc_sigmask(void *sc_ptr);
extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index d49a34f0bee8..ec7dc1a65465 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -8,7 +8,7 @@
extern void timer(void);
extern void switch_timers(int to_real);
-extern void user_time_init(void);
+extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
extern void enable_timer(void);
extern void time_lock(void);
diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h
new file mode 100644
index 000000000000..3c5660ff97d7
--- /dev/null
+++ b/arch/um/include/um_mmu.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __ARCH_UM_MMU_H
+#define __ARCH_UM_MMU_H
+
+#include "linux/config.h"
+#include "choose-mode.h"
+
+#ifdef CONFIG_MODE_TT
+#include "../kernel/tt/include/mmu.h"
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+#include "../kernel/skas/include/mmu.h"
+#endif
+
+typedef union {
+#ifdef CONFIG_MODE_TT
+ struct mmu_context_tt tt;
+#endif
+#ifdef CONFIG_MODE_SKAS
+ struct mmu_context_skas skas;
+#endif
+} mm_context_t;
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
new file mode 100644
index 000000000000..41afa3a8f086
--- /dev/null
+++ b/arch/um/include/um_uaccess.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __ARCH_UM_UACCESS_H
+#define __ARCH_UM_UACCESS_H
+
+#include "linux/config.h"
+#include "choose-mode.h"
+
+#ifdef CONFIG_MODE_TT
+#include "../kernel/tt/include/uaccess.h"
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+#include "../kernel/skas/include/uaccess.h"
+#endif
+
+#define access_ok(type, addr, size) \
+ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
+
+static inline int verify_area(int type, const void * addr, unsigned long size)
+{
+ return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
+ size));
+}
+
+static inline int copy_from_user(void *to, const void *from, int n)
+{
+ return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
+ from, n));
+}
+
+static inline int copy_to_user(void *to, const void *from, int n)
+{
+ return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to,
+ from, n));
+}
+
+static inline int strncpy_from_user(char *dst, const char *src, int count)
+{
+ return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
+ dst, src, count));
+}
+
+static inline int __clear_user(void *mem, int len)
+{
+ return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
+}
+
+static inline int clear_user(void *mem, int len)
+{
+ return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
+}
+
+static inline int strnlen_user(const void *str, int len)
+{
+ return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 5f50aed753b2..a419cc9ccfff 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -8,6 +8,8 @@
#include "sysdep/ptrace.h"
+extern int mode_tt;
+
extern int grantpt(int __fd);
extern int unlockpt(int __fd);
extern char *ptsname(int __fd);
@@ -21,6 +23,13 @@ struct cpu_task {
extern struct cpu_task cpu_tasks[];
+struct signal_info {
+ void (*handler)(int, struct uml_pt_regs *);
+ int is_irq;
+};
+
+extern struct signal_info sig_info[];
+
extern unsigned long low_physmem;
extern unsigned long high_physmem;
extern unsigned long uml_physmem;
@@ -29,16 +38,11 @@ extern unsigned long end_vm;
extern unsigned long start_vm;
extern unsigned long highmem;
-extern int tracing_pid;
-extern int honeypot;
-
extern char host_info[];
extern char saved_command_line[];
extern char command_line[];
-extern int gdb_pid;
-
extern char *tempdir;
extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
@@ -51,12 +55,10 @@ extern int pty_close_sigio;
extern void stop(void);
extern void stack_protections(unsigned long address);
extern void task_protections(unsigned long address);
-extern int signals(int (*init_proc)(void *), void *sp);
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern void *add_signal_handler(int sig, void (*handler)(int));
extern int start_fork_tramp(void *arg, unsigned long temp_stack,
int clone_flags, int (*tramp)(void *));
-extern void trace_myself(void);
extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
extern int linux_main(int argc, char **argv);
extern void remap_data(void *segment_start, void *segment_end, int w);
@@ -69,13 +71,12 @@ extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
extern void add_arg(char *cmd_line, char *arg);
-extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
-extern void attach_process(int pid);
-extern int fork_tramp(void *sig_stack);
+extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
+extern void init_new_thread_signals(int altstack);
extern void do_exec(int old_pid, int new_pid);
extern void tracer_panic(char *msg, ...);
extern char *get_umid(int only_if_set);
-extern void do_longjmp(void *p);
+extern void do_longjmp(void *p, int val);
extern void suspend_new_thread(int fd);
extern int detach(int pid, int sig);
extern int attach(int pid);
@@ -89,7 +90,8 @@ extern void arch_check_bugs(void);
extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
extern void forward_pending_sigio(int target);
-
+extern int can_do_skas(void);
+
#endif
/*
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 82736d449d8b..de98110a7494 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -1,40 +1,47 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
EXTRA_TARGETS := unmap_fin.o
-obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \
+obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \
helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \
syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \
- time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
+ time_kern.o tlb.o trap_kern.o trap_user.o um_arch.o \
umid.o user_util.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
+obj-$(CONFIG_GPROF) += gprof_syms.o
+obj-$(CONFIG_GCOV) += gmon_syms.o
+obj-$(CONFIG_TTY_LOG) += tty_log.o
-# user_syms.o not included here because kbuild has its own ideas about
-# building anything in export-objs
+obj-$(CONFIG_MODE_TT) += tt/
+obj-$(CONFIG_MODE_SKAS) += skas/
-USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \
- tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
-USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file))
+user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o
+# user_syms.o not included here because Rules.make has its own ideas about
+# building anything in export-objs
+
+USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \
+ process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
-ifeq ($(CONFIG_MODULES), y)
- DMODULES = -D__CONFIG_MODULES__
-endif
+DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__
+DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__
-ifeq ($(CONFIG_MODVERSIONS), y)
- DMODVERSIONS = -D__CONFIG_MODVERSIONS__
-endif
+export-objs-$(CONFIG_GPROF) += gprof_syms.o
+export-objs-$(CONFIG_GCOV) += gmon_syms.o
-obj-$(CONFIG_GPROF) += gprof_syms.o
-obj-$(CONFIG_GCOV) += gmon_syms.o
-obj-$(CONFIG_TTY_LOG) += tty_log.o
+export-objs := ksyms.o process_kern.o signal_kern.o $(export-objs-y)
-CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) \
+CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
-I/usr/include -I../include
CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
@@ -42,27 +49,28 @@ CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
-arch/um/kernel/unmap.o: arch/um/kernel/unmap.c
+$(obj)/unmap.o: $(src)/unmap.c
$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
-arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o
+$(obj)/unmap_fin.o : $(src)/unmap.o
ld -r -o $@ $< -lc -L/usr/lib
# This has to be separate because it needs be compiled with frame pointers
# regardless of how the rest of the kernel is built.
-arch/um/kernel/frame.o: arch/um/kernel/frame.c
+$(obj)/frame.o: $(src)/frame.c
$(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
-arch/um/kernel/config.c : arch/um/kernel/config.c.in $(TOPDIR)/.config
- $(PERL) -e $(QUOTE) < arch/um/kernel/config.c.in > $@
+$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config
+ $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@
-arch/um/kernel/config.o : arch/um/kernel/config.c
+$(obj)/config.o : $(obj)/config.c
clean:
rm -f config.c
+ for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
modules:
diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c
new file mode 100644
index 000000000000..6e27cb032258
--- /dev/null
+++ b/arch/um/kernel/checksum.c
@@ -0,0 +1,42 @@
+#include "asm/uaccess.h"
+#include "linux/errno.h"
+
+extern unsigned int arch_csum_partial(const char *buff, int len, int sum);
+
+extern unsigned int csum_partial(char *buff, int len, int sum)
+{
+ return(arch_csum_partial(buff, len, sum));
+}
+
+unsigned int csum_partial_copy_to(const char *src, char *dst, int len,
+ int sum, int *err_ptr)
+{
+ if(copy_to_user(dst, src, len)){
+ *err_ptr = -EFAULT;
+ return(-1);
+ }
+
+ return(arch_csum_partial(src, len, sum));
+}
+
+unsigned int csum_partial_copy_from(const char *src, char *dst, int len,
+ int sum, int *err_ptr)
+{
+ if(copy_from_user(dst, src, len)){
+ *err_ptr = -EFAULT;
+ return(-1);
+ }
+
+ return(arch_csum_partial(dst, len, sum));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index 353bfa4da610..eaae628fa902 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -18,65 +18,17 @@
#include "2_5compat.h"
#include "os.h"
#include "time_user.h"
-
-/* See comment above fork_tramp for why sigstop is defined and used like
- * this
- */
-
-static int sigstop = SIGSTOP;
-
-static int exec_tramp(void *sig_stack)
-{
- int sig = sigstop;
-
- init_new_thread(sig_stack, NULL);
- kill(os_getpid(), sig);
- return(0);
-}
+#include "choose-mode.h"
+#include "mode_kern.h"
void flush_thread(void)
{
- unsigned long stack;
- int new_pid;
-
- stack = alloc_stack(0, 0);
- if(stack == 0){
- printk(KERN_ERR
- "flush_thread : failed to allocate temporary stack\n");
- do_exit(SIGKILL);
- }
-
- new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
- stack, 0, exec_tramp);
- if(new_pid < 0){
- printk(KERN_ERR
- "flush_thread : new thread failed, errno = %d\n",
- -new_pid);
- do_exit(SIGKILL);
- }
-
- if(current->thread_info->cpu == 0)
- forward_interrupts(new_pid);
- current->thread.request.op = OP_EXEC;
- current->thread.request.u.exec.pid = new_pid;
- unprotect_stack((unsigned long) current->thread_info);
- os_usr1_process(os_getpid());
-
- enable_timer();
- free_page(stack);
- protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
- task_protections((unsigned long) current->thread_info);
- force_flush_all();
- unblock_signals();
+ CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
}
void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
{
- set_fs(USER_DS);
- flush_tlb_mm(current->mm);
- PT_REGS_IP(regs) = eip;
- PT_REGS_SP(regs) = esp;
- PT_FIX_EXEC_STACK(esp);
+ CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
}
static int execve1(char *file, char **argv, char **env)
@@ -93,8 +45,12 @@ static int execve1(char *file, char **argv, char **env)
int um_execve(char *file, char **argv, char **env)
{
- if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp);
- return(-1);
+ int err;
+
+ err = execve1(file, argv, env);
+ if(!err)
+ do_longjmp(current->thread.exec_buf, 1);
+ return(err);
}
int sys_execve(char *file, char **argv, char **env)
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index 788f914d8510..14a748e2e25a 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -42,7 +42,7 @@ static int write_proc_exitcode(struct file *file, const char *buffer,
return(count);
}
-int make_proc_exitcode(void)
+static int make_proc_exitcode(void)
{
struct proc_dir_entry *ent;
diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c
index 28793041426a..ae5b0e3e5158 100644
--- a/arch/um/kernel/frame.c
+++ b/arch/um/kernel/frame.c
@@ -12,6 +12,7 @@
#include <sched.h>
#include <errno.h>
#include <sys/ptrace.h>
+#include <sys/syscall.h>
#include <sys/mman.h>
#include <asm/page.h>
#include <asm/ptrace.h>
@@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
}
- if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
- printf("capture_stack : Expected exit status 0, "
+ if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
+ printf("capture_stack : Expected exit signal 9, "
"got status = 0x%x\n", status);
exit(1);
}
@@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
return(len);
}
-static void child_common(void *sp, int size, sighandler_t handler, int flags)
+struct common_raw {
+ void *stack;
+ int size;
+ unsigned long sig;
+ unsigned long sr;
+ unsigned long sp;
+};
+
+#define SA_RESTORER (0x04000000)
+
+typedef unsigned long old_sigset_t;
+
+struct old_sigaction {
+ __sighandler_t handler;
+ old_sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+};
+
+static void child_common(struct common_raw *common, sighandler_t handler,
+ int restorer, int flags)
{
- stack_t ss;
- struct sigaction sa;
+ stack_t ss = ((stack_t) { .ss_sp = common->stack,
+ .ss_flags = 0,
+ .ss_size = common->size });
+ int err;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
printf("PTRACE_TRACEME failed, errno = %d\n", errno);
}
- ss.ss_sp = sp;
- ss.ss_flags = 0;
- ss.ss_size = size;
if(sigaltstack(&ss, NULL) < 0){
printf("sigaltstack failed - errno = %d\n", errno);
- _exit(1);
+ kill(getpid(), SIGKILL);
}
- sa.sa_handler = handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_ONSTACK | flags;
- if(sigaction(SIGUSR1, &sa, NULL) < 0){
+ if(restorer){
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_ONSTACK | flags;
+ err = sigaction(SIGUSR1, &sa, NULL);
+ }
+ else {
+ struct old_sigaction sa;
+
+ sa.handler = handler;
+ sa.sa_mask = 0;
+ sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
+ err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
+ }
+
+ if(err < 0){
printf("sigaction failed - errno = %d\n", errno);
- _exit(1);
+ kill(getpid(), SIGKILL);
}
os_stop_process(os_getpid());
@@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags)
/* Changed only during early boot */
struct sc_frame signal_frame_sc;
+struct sc_frame signal_frame_sc_sr;
+
struct sc_frame_raw {
- void *stack;
- int size;
- unsigned long sig;
+ struct common_raw common;
unsigned long sc;
- unsigned long sr;
- unsigned long sp;
+ int restorer;
struct arch_frame_data_raw arch;
};
@@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL;
static void sc_handler(int sig, struct sigcontext sc)
{
- raw_sc->sig = (unsigned long) &sig;
+ raw_sc->common.sig = (unsigned long) &sig;
+ raw_sc->common.sr = frame_restorer();
+ raw_sc->common.sp = frame_sp();
raw_sc->sc = (unsigned long) &sc;
- raw_sc->sr = frame_restorer();
- raw_sc->sp = frame_sp();
setup_arch_frame_raw(&raw_sc->arch, &sc);
os_stop_process(os_getpid());
- _exit(0);
+ kill(getpid(), SIGKILL);
}
static int sc_child(void *arg)
{
raw_sc = arg;
- child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler,
- 0);
+ child_common(&raw_sc->common, (sighandler_t) sc_handler,
+ raw_sc->restorer, 0);
return(-1);
}
@@ -169,13 +202,9 @@ static int sc_child(void *arg)
struct si_frame signal_frame_si;
struct si_frame_raw {
- void *stack;
- int size;
- unsigned long sig;
+ struct common_raw common;
unsigned long sip;
unsigned long si;
- unsigned long sr;
- unsigned long sp;
};
/* Changed only during early boot */
@@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL;
static void si_handler(int sig, siginfo_t *si)
{
- raw_si->sig = (unsigned long) &sig;
+ raw_si->common.sig = (unsigned long) &sig;
+ raw_si->common.sr = frame_restorer();
+ raw_si->common.sp = frame_sp();
raw_si->sip = (unsigned long) &si;
raw_si->si = (unsigned long) si;
- raw_si->sr = frame_restorer();
- raw_si->sp = frame_sp();
os_stop_process(os_getpid());
- _exit(0);
+ kill(getpid(), SIGKILL);
}
static int si_child(void *arg)
{
raw_si = arg;
- child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler,
- SA_SIGINFO);
+ child_common(&raw_si->common, (sighandler_t) si_handler, 1,
+ SA_SIGINFO);
return(-1);
}
+static int relative_sr(unsigned long sr, int sr_index, void *stack,
+ void *framep)
+{
+ unsigned long *srp = (unsigned long *) sr;
+ unsigned long frame = (unsigned long) framep;
+
+ if((*srp & PAGE_MASK) == (unsigned long) stack){
+ *srp -= sr;
+ *((unsigned long *) (frame + sr_index)) = *srp;
+ return(1);
+ }
+ else return(0);
+}
+
+static unsigned long capture_stack_common(int (*proc)(void *), void *arg,
+ struct common_raw *common_in,
+ void *top, void *sigstack,
+ int stack_len,
+ struct frame_common *common_out)
+{
+ unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
+
+ common_in->stack = (void *) sigstack;
+ common_in->size = stack_len;
+ common_out->len = capture_stack(proc, arg, top, sig_top,
+ &common_out->data);
+ base = sig_top - common_out->len;
+ common_out->sig_index = common_in->sig - base;
+ common_out->sp_index = common_in->sp - base;
+ common_out->sr_index = common_in->sr - base;
+ common_out->sr_relative = relative_sr(common_in->sr,
+ common_out->sr_index, sigstack,
+ common_out->data);
+ return(base);
+}
+
void capture_signal_stack(void)
{
struct sc_frame_raw raw_sc;
@@ -220,54 +285,29 @@ void capture_signal_stack(void)
top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
sig_top = (unsigned long) sigstack + PAGE_SIZE;
- raw_sc.stack = sigstack;
- raw_sc.size = PAGE_SIZE;
- signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
- sig_top, &signal_frame_sc.data);
-
- /* These are the offsets within signal_frame_sc.data (counting from
- * the bottom) of sig, sc, SA_RESTORER, and the initial sp.
- */
+ /* Get the sigcontext, no sigrestorer layout */
+ raw_sc.restorer = 0;
+ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
+ (void *) top, sigstack, PAGE_SIZE,
+ &signal_frame_sc.common);
- base = sig_top - signal_frame_sc.len;
- signal_frame_sc.sig_index = raw_sc.sig - base;
signal_frame_sc.sc_index = raw_sc.sc - base;
- signal_frame_sc.sr_index = raw_sc.sr - base;
- if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) ==
- (unsigned long) sigstack){
- unsigned long *sr = (unsigned long *) raw_sc.sr;
- unsigned long frame = (unsigned long) signal_frame_sc.data;
-
- signal_frame_sc.sr_relative = 1;
- *sr -= raw_sc.sr;
- *((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
- }
- else signal_frame_sc.sr_relative = 0;
- signal_frame_sc.sp_index = raw_sc.sp - base;
setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
- /* Repeat for the siginfo variant */
+ /* Ditto for the sigcontext, sigrestorer layout */
+ raw_sc.restorer = 1;
+ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
+ (void *) top, sigstack, PAGE_SIZE,
+ &signal_frame_sc_sr.common);
+ signal_frame_sc_sr.sc_index = raw_sc.sc - base;
+
+ /* And the siginfo layout */
- raw_si.stack = sigstack;
- raw_si.size = PAGE_SIZE;
- signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
- sig_top, &signal_frame_si.data);
- base = sig_top - signal_frame_si.len;
- signal_frame_si.sig_index = raw_si.sig - base;
+ base = capture_stack_common(si_child, &raw_si, &raw_si.common,
+ (void *) top, sigstack, PAGE_SIZE,
+ &signal_frame_si.common);
signal_frame_si.sip_index = raw_si.sip - base;
signal_frame_si.si_index = raw_si.si - base;
- signal_frame_si.sr_index = raw_si.sr - base;
- if((*((unsigned long *) raw_si.sr) & PAGE_MASK) ==
- (unsigned long) sigstack){
- unsigned long *sr = (unsigned long *) raw_si.sr;
- unsigned long frame = (unsigned long) signal_frame_si.data;
-
- signal_frame_sc.sr_relative = 1;
- *sr -= raw_si.sr;
- *((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
- }
- else signal_frame_si.sr_relative = 0;
- signal_frame_si.sp_index = raw_si.sp - base;
if((munmap(stack, PAGE_SIZE) < 0) ||
(munmap(sigstack, PAGE_SIZE) < 0)){
@@ -277,14 +317,6 @@ void capture_signal_stack(void)
}
}
-void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
-{
- struct sigcontext *sc = sc_ptr;
-
- SC_IP(sc) = ip;
- SC_SP(sc) = sp;
-}
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c
index f71451c4c780..cd2177629bec 100644
--- a/arch/um/kernel/frame_kern.c
+++ b/arch/um/kernel/frame_kern.c
@@ -9,20 +9,31 @@
#include "frame_kern.h"
#include "sigcontext.h"
#include "sysdep/ptrace.h"
+#include "choose-mode.h"
+#include "mode.h"
static int copy_restorer(void (*restorer)(void), unsigned long start,
unsigned long sr_index, int sr_relative)
{
- if(restorer != 0){
- if(copy_to_user((void *) (start + sr_index), &restorer,
- sizeof(restorer)))
- return(1);
- }
- else if(sr_relative){
- unsigned long *sr = (unsigned long *) (start + sr_index);
- *sr += (unsigned long) sr;
+ unsigned long sr;
+
+ if(sr_relative){
+ sr = (unsigned long) restorer;
+ sr += start + sr_index;
+ restorer = (void (*)(void)) sr;
}
- return(0);
+
+ return(copy_to_user((void *) (start + sr_index), &restorer,
+ sizeof(restorer)));
+}
+
+static int copy_sc_to_user(void *to, struct pt_regs *from)
+{
+ return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt,
+ &signal_frame_sc_sr.arch),
+ copy_sc_to_user_skas(to, &from->regs,
+ current->thread.cr2,
+ current->thread.err)));
}
int setup_signal_stack_si(unsigned long stack_top, int sig,
@@ -34,27 +45,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
void *sip;
int sig_size = _NSIG_WORDS * sizeof(unsigned long);
- start = stack_top - signal_frame_si.len -
+ start = stack_top - signal_frame_si.common.len -
sc_size(&signal_frame_sc.arch) - sig_size;
sip = (void *) (start + signal_frame_si.si_index);
- sc = start + signal_frame_si.len;
+ sc = start + signal_frame_si.common.len;
sigs = sc + sc_size(&signal_frame_sc.arch);
- if(copy_sc_to_user((void *) sc, regs->regs.sc,
- &signal_frame_sc.arch) ||
- copy_to_user((void *) start, signal_frame_si.data,
- signal_frame_si.len) ||
- copy_to_user((void *) (start + signal_frame_si.sig_index), &sig,
- sizeof(sig)) ||
+
+ if(restorer == NULL)
+ panic("setup_signal_stack_si - no restorer");
+
+ if(copy_sc_to_user((void *) sc, regs) ||
+ copy_to_user((void *) start, signal_frame_si.common.data,
+ signal_frame_si.common.len) ||
+ copy_to_user((void *) (start + signal_frame_si.common.sig_index),
+ &sig, sizeof(sig)) ||
copy_siginfo_to_user(sip, info) ||
copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
sizeof(sip)) ||
copy_to_user((void *) sigs, mask, sig_size) ||
- copy_restorer(restorer, start, signal_frame_si.sr_index,
- signal_frame_si.sr_relative))
+ copy_restorer(restorer, start, signal_frame_si.common.sr_index,
+ signal_frame_si.common.sr_relative))
return(1);
PT_REGS_IP(regs) = handler;
- PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+ PT_REGS_SP(regs) = start + signal_frame_sc.common.sp_index;
return(0);
}
@@ -62,26 +76,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
unsigned long handler, void (*restorer)(void),
struct pt_regs *regs, sigset_t *mask)
{
+ struct frame_common *frame = &signal_frame_sc_sr.common;
+ void *user_sc;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
- unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size;
- void *user_sc = (void *) (start + signal_frame_sc.sc_index);
+ unsigned long sigs, sr;
+ unsigned long start = stack_top - frame->len - sig_size;
+
+ user_sc = (void *) (start + signal_frame_sc_sr.sc_index);
+ if(restorer == NULL){
+ frame = &signal_frame_sc.common;
+ user_sc = (void *) (start + signal_frame_sc.sc_index);
+ sr = (unsigned long) frame->data;
+ sr += frame->sr_index;
+ sr = *((unsigned long *) sr);
+ restorer = ((void (*)(void)) sr);
+ }
- sigs = start + signal_frame_sc.len;
- if(copy_to_user((void *) start, signal_frame_sc.data,
- signal_frame_sc.len) ||
- copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
+ sigs = start + frame->len;
+ if(copy_to_user((void *) start, frame->data, frame->len) ||
+ copy_to_user((void *) (start + frame->sig_index), &sig,
sizeof(sig)) ||
- copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) ||
+ copy_sc_to_user(user_sc, regs) ||
copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
- copy_restorer(restorer, start, signal_frame_sc.sr_index,
- signal_frame_sc.sr_relative))
+ copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
return(1);
PT_REGS_IP(regs) = handler;
- PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+ PT_REGS_SP(regs) = start + frame->sp_index;
- set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
return(0);
}
diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
index 5d8fb7bba2b1..5c4b27942da3 100644
--- a/arch/um/kernel/helper.c
+++ b/arch/um/kernel/helper.c
@@ -43,9 +43,12 @@ static int helper_child(void *arg)
execvp(argv[0], argv);
printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
write(data->fd, &errno, sizeof(errno));
- _exit(1);
+ os_kill_process(os_getpid(), 0);
+ return(0);
}
+/* XXX The alloc_stack here breaks if this is called in the tracing thread */
+
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
unsigned long *stack_out)
{
@@ -86,7 +89,10 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
errno);
return(-errno);
}
- else if(n != 0) pid = -err;
+ else if(n != 0){
+ waitpid(pid, NULL, 0);
+ pid = -err;
+ }
if(stack_out == NULL) free_stack(stack, 0);
else *stack_out = stack;
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index f06162f5a113..c9bc00a19403 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -47,7 +47,7 @@ struct task_struct *alloc_task_struct(void){
void unprotect_stack(unsigned long stack)
{
- protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
+ protect_memory(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
}
void free_task_struct(struct task_struct *task)
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
index a5abb61536cf..239a6a6126c9 100644
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -188,7 +188,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
pollfds_size++;
}
- if(type == IRQ_WRITE) events = 0;
+ if(type == IRQ_WRITE)
+ fd = -1;
pollfds[pollfds_num] = ((struct pollfd) { fd : fd,
events : events,
@@ -337,6 +338,7 @@ void reactivate_fd(int fd, int irqnum)
irq_unlock(flags);
return;
}
+
pollfds[i].fd = irq->fd;
irq_unlock(flags);
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 28e728347041..7de3e05edbab 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#include "linux/config.h"
#include "linux/module.h"
#include "linux/string.h"
@@ -19,17 +24,13 @@
EXPORT_SYMBOL(stop);
EXPORT_SYMBOL(uml_physmem);
EXPORT_SYMBOL(set_signals);
+EXPORT_SYMBOL(get_signals);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(sys_waitpid);
EXPORT_SYMBOL(task_size);
-EXPORT_SYMBOL(__do_copy_from_user);
-EXPORT_SYMBOL(__do_copy_to_user);
-EXPORT_SYMBOL(__do_strncpy_from_user);
-EXPORT_SYMBOL(__do_strnlen_user);
EXPORT_SYMBOL(flush_tlb_range);
-EXPORT_SYMBOL(__do_clear_user);
-EXPORT_SYMBOL(honeypot);
EXPORT_SYMBOL(host_task_size);
EXPORT_SYMBOL(arch_validate);
@@ -37,10 +38,10 @@ EXPORT_SYMBOL(region_pa);
EXPORT_SYMBOL(region_va);
EXPORT_SYMBOL(phys_mem_map);
EXPORT_SYMBOL(page_mem_map);
-EXPORT_SYMBOL(get_signals);
EXPORT_SYMBOL(page_to_phys);
EXPORT_SYMBOL(phys_to_page);
EXPORT_SYMBOL(high_physmem);
+EXPORT_SYMBOL(empty_zero_page);
EXPORT_SYMBOL(os_open_file);
EXPORT_SYMBOL(os_read_file);
@@ -53,7 +54,6 @@ EXPORT_SYMBOL(helper_wait);
EXPORT_SYMBOL(os_shutdown_socket);
EXPORT_SYMBOL(os_connect_socket);
EXPORT_SYMBOL(run_helper);
-EXPORT_SYMBOL(tracing_pid);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(dump_thread);
@@ -75,6 +75,7 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed);
extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
+EXPORT_SYMBOL(smp_num_cpus);
#endif
#ifdef CONFIG_HIGHMEM
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 5a582a8de7d1..178223bf2bfa 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -25,6 +25,8 @@
#include "mem.h"
#include "kern.h"
#include "init.h"
+#include "os.h"
+#include "mode_kern.h"
/* Changed during early boot */
pgd_t swapper_pg_dir[1024];
@@ -56,12 +58,12 @@ static unsigned long brk_end;
static void map_cb(void *unused)
{
- map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
}
void unmap_physmem(void)
{
- unmap((void *) brk_end, uml_reserved - brk_end);
+ os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
}
extern char __binary_start;
@@ -81,17 +83,17 @@ void mem_init(void)
/* Map in the area just after the brk now that kmalloc is about
* to be turned on.
*/
- brk_end = (unsigned long) ROUND_UP(sbrk(0));
+ brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
map_cb(NULL);
- tracing_cb(map_cb, NULL);
+ initial_thread_cb(map_cb, NULL);
free_bootmem(__pa(brk_end), uml_reserved - brk_end);
uml_reserved = brk_end;
/* Fill in any hole at the start of the binary */
start = (unsigned long) &__binary_start;
if(uml_physmem != start){
- map(uml_physmem, __pa(uml_physmem), start - uml_physmem,
- 1, 1, 0);
+ map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
+ 1, 1, 0);
}
/* this will put all low memory onto the freelists */
@@ -106,6 +108,21 @@ void mem_init(void)
kmalloc_ok = 1;
}
+/* Changed during early boot */
+static unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+ if(kmem_top == 0)
+ kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
+ return(kmem_top);
+}
+
+void set_kmem_end(unsigned long new)
+{
+ kmem_top = new;
+}
+
#if CONFIG_HIGHMEM
/* Changed during early boot */
pte_t *kmap_pte;
@@ -379,20 +396,6 @@ void show_mem(void)
printk("%d pages swap cached\n", cached);
}
-/* Changed during early boot */
-static unsigned long kmem_top = 0;
-
-unsigned long get_kmem_end(void)
-{
- if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM;
- return(kmem_top);
-}
-
-void set_kmem_end(unsigned long new)
-{
- kmem_top = new;
-}
-
static int __init uml_mem_setup(char *line, int *add)
{
char *retptr;
@@ -411,28 +414,8 @@ __uml_setup("mem=", uml_mem_setup,
struct page *arch_validate(struct page *page, int mask, int order)
{
- unsigned long addr, zero = 0;
- int i;
-
- again:
- if(page == NULL) return(page);
- if(PageHighMem(page)) return(page);
-
- addr = (unsigned long) page_address(page);
- for(i = 0; i < (1 << order); i++){
- current->thread.fault_addr = (void *) addr;
- if(__do_copy_to_user((void *) addr, &zero,
- sizeof(zero),
- &current->thread.fault_addr,
- &current->thread.fault_catcher)){
- if(!(mask & __GFP_WAIT)) return(NULL);
- else break;
- }
- addr += PAGE_SIZE;
- }
- if(i == (1 << order)) return(page);
- page = alloc_pages(mask, order);
- goto again;
+ return(CHOOSE_MODE_PROC(arch_validate_tt, arch_validate_skas, page,
+ mask, order));
}
DECLARE_MUTEX(vm_reserved_sem);
@@ -513,7 +496,7 @@ unsigned long get_vm(unsigned long len)
return(0);
found:
up(&vm_reserved_sem);
- start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE;
+ start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE;
err = reserve_vm(start, start + len, NULL);
if(err) return(0);
return(start);
@@ -562,7 +545,7 @@ struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =
int num_iomem_regions = 0;
-void add_iomem(char *name, int fd, int size)
+void add_iomem(char *name, int fd, unsigned long size)
{
if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
return;
diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
index af857510d17a..d90345b5fd44 100644
--- a/arch/um/kernel/mem_user.c
+++ b/arch/um/kernel/mem_user.c
@@ -181,44 +181,22 @@ void log(char *fmt, ...)
}
#endif
-void map(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x)
+int map_memory(unsigned long virt, unsigned long phys, unsigned long len,
+ int r, int w, int x)
{
- struct mem_region *region;
- void *loc;
- int prot;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
- region = phys_region(phys);
-
- loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
- region->fd, phys_offset(phys));
- if(loc != (void *) virt){
- panic("Error mapping a page - errno = %d", errno);
- }
-}
-
-int unmap(void *addr, int len)
-{
- int err;
+ struct mem_region *region = phys_region(phys);
- err = munmap(addr, len);
- if(err < 0) return(-errno);
- else return(err);
+ return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len,
+ r, w, x));
}
-int protect(unsigned long addr, unsigned long len, int r, int w, int x,
- int must_succeed)
+int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
+ int must_succeed)
{
- int prot;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
- if(mprotect((void *) addr, len, prot) == -1){
- if(must_succeed)
- panic("protect failed, errno = %d", errno);
- else return(-errno);
+ if(os_protect_memory((void *) addr, len, r, w, x) < 0){
+ if(must_succeed)
+ panic("protect failed, errno = %d", errno);
+ else return(-errno);
}
return(0);
}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index d410aaa7332b..44e9a980949f 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -21,9 +21,6 @@
#include <asm/sigcontext.h>
#include <asm/unistd.h>
#include <asm/page.h>
-#ifdef PROFILING
-#include <sys/gmon.h>
-#endif
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
@@ -33,13 +30,19 @@
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
#include "irq_user.h"
-#include "syscall_user.h"
#include "ptrace_user.h"
#include "time_user.h"
#include "init.h"
#include "os.h"
+#include "uml-config.h"
+#include "choose-mode.h"
+#include "mode.h"
+#ifdef CONFIG_MODE_SKAS
+#include "skas_ptrace.h"
+#include "skas.h"
+#endif
-void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
+void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
{
int flags = 0;
@@ -47,6 +50,13 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
set_sigstack(sig_stack, 2 * page_size());
flags = SA_ONSTACK;
}
+ if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+}
+
+void init_new_thread_signals(int altstack)
+{
+ int flags = altstack ? SA_ONSTACK : 0;
+
set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
@@ -61,11 +71,10 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGUSR2, (__sighandler_t) sig_handler,
SA_NOMASK | flags, -1);
- if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
- signal(SIGCHLD, SIG_IGN);
+ (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0);
signal(SIGHUP, SIG_IGN);
- init_irq_signals(sig_stack != NULL);
+ init_irq_signals(altstack);
}
struct tramp {
@@ -122,32 +131,6 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
return(arg.pid);
}
-void trace_myself(void)
-{
- if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
- panic("ptrace failed in trace_myself");
-}
-
-void attach_process(int pid)
-{
- if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
- (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
- tracer_panic("OP_FORK failed to attach pid");
- wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
- if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
- tracer_panic("OP_FORK failed to continue process");
-}
-
-void tracer_panic(char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vprintf(format, ap);
- printf("\n");
- while(1) sleep(10);
-}
-
void suspend_new_thread(int fd)
{
char c;
@@ -164,19 +147,18 @@ static int ptrace_child(void *arg)
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
perror("ptrace");
- _exit(1);
+ os_kill_process(pid, 0);
}
os_stop_process(pid);
_exit(os_getpid() == pid);
}
-void __init check_ptrace(void)
+static int start_ptraced_child(void **stack_out)
{
void *stack;
unsigned long sp;
- int status, pid, n, syscall;
-
- printk("Checking that ptrace can change system call numbers...");
+ int pid, n, status;
+
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(stack == MAP_FAILED)
@@ -191,6 +173,33 @@ void __init check_ptrace(void)
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
panic("check_ptrace : expected SIGSTOP, got status = %d",
status);
+
+ *stack_out = stack;
+ return(pid);
+}
+
+static void stop_ptraced_child(int pid, void *stack, int exitcode)
+{
+ int status, n;
+
+ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+ panic("check_ptrace : ptrace failed, errno = %d", errno);
+ n = waitpid(pid, &status, 0);
+ if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode))
+ panic("check_ptrace : child exited with status 0x%x", status);
+
+ if(munmap(stack, PAGE_SIZE) < 0)
+ panic("check_ptrace : munmap failed, errno = %d", errno);
+}
+
+void __init check_ptrace(void)
+{
+ void *stack;
+ int pid, syscall, n, status;
+
+ printk("Checking that ptrace can change system call numbers...");
+ pid = start_ptraced_child(&stack);
+
while(1){
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d",
@@ -213,23 +222,19 @@ void __init check_ptrace(void)
break;
}
}
- if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
- panic("check_ptrace : ptrace failed, errno = %d", errno);
- n = waitpid(pid, &status, 0);
- if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
- panic("check_ptrace : child exited with status 0x%x", status);
-
- if(munmap(stack, PAGE_SIZE) < 0)
- panic("check_ptrace : munmap failed, errno = %d", errno);
+ stop_ptraced_child(pid, stack, 0);
printk("OK\n");
}
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
jmp_buf buf;
+ int n;
*jmp_ptr = &buf;
- if(setjmp(buf)) return(1);
+ n = setjmp(buf);
+ if(n != 0)
+ return(n);
(*fn)(arg);
return(0);
}
@@ -244,6 +249,41 @@ void forward_pending_sigio(int target)
kill(target, SIGIO);
}
+int can_do_skas(void)
+{
+#ifdef CONFIG_MODE_SKAS
+ struct ptrace_faultinfo fi;
+ void *stack;
+ int pid, n, ret = 1;
+
+ printk("Checking for the skas3 patch in the host...");
+ pid = start_ptraced_child(&stack);
+
+ n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
+ if(n < 0){
+ if(errno == EIO)
+ printk("not found\n");
+ else printk("No (unexpected errno - %d)\n", errno);
+ ret = 0;
+ }
+ else printk("found\n");
+
+ init_registers(pid);
+ stop_ptraced_child(pid, stack, 1);
+
+ printk("Checking for /proc/mm...");
+ if(access("/proc/mm", W_OK)){
+ printk("not found\n");
+ ret = 0;
+ }
+ else printk("found\n");
+
+ return(ret);
+#else
+ return(0);
+#endif
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 1588e175b4db..faf8609ceaf8 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -40,6 +40,9 @@
#include "sigcontext.h"
#include "2_5compat.h"
#include "os.h"
+#include "mode.h"
+#include "mode_kern.h"
+#include "choose-mode.h"
/* This is a per-cpu array. A processor only modifies its entry and it only
* cares about its entry, so it's OK if another processor is modifying its
@@ -64,26 +67,11 @@ struct task_struct *get_task(int pid, int require)
return(ret);
}
-int is_valid_pid(int pid)
-{
- struct task_struct *task;
-
- read_lock(&tasklist_lock);
- for_each_process(task){
- if(task->thread.extern_pid == pid){
- read_unlock(&tasklist_lock);
- return(1);
- }
- }
- read_unlock(&tasklist_lock);
- return(0);
-}
-
int external_pid(void *t)
{
struct task_struct *task = t ? t : current;
- return(task->thread.extern_pid);
+ return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
}
int pid_to_processor_id(int pid)
@@ -101,37 +89,6 @@ void free_stack(unsigned long stack, int order)
free_pages(stack, order);
}
-void set_init_pid(int pid)
-{
- int err;
-
- init_task.thread.extern_pid = pid;
- err = os_pipe(init_task.thread.switch_pipe, 1, 1);
- if(err) panic("Can't create switch pipe for init_task, errno = %d",
- err);
-}
-
-int set_user_mode(void *t)
-{
- struct task_struct *task;
-
- task = t ? t : current;
- if(task->thread.tracing) return(1);
- task->thread.request.op = OP_TRACE_ON;
- os_usr1_process(os_getpid());
- return(0);
-}
-
-void set_tracing(void *task, int tracing)
-{
- ((struct task_struct *) task)->thread.tracing = tracing;
-}
-
-int is_tracing(void *t)
-{
- return (((struct task_struct *) t)->thread.tracing);
-}
-
unsigned long alloc_stack(int order, int atomic)
{
unsigned long page;
@@ -144,53 +101,13 @@ unsigned long alloc_stack(int order, int atomic)
return(page);
}
-extern void schedule_tail(struct task_struct *prev);
-
-static void new_thread_handler(int sig)
-{
- int (*fn)(void *);
- void *arg;
-
- fn = current->thread.request.u.thread.proc;
- arg = current->thread.request.u.thread.arg;
- current->thread.regs.regs.sc = (void *) (&sig + 1);
- suspend_new_thread(current->thread.switch_pipe[0]);
-
- block_signals();
-#ifdef CONFIG_SMP
- schedule_tail(NULL);
-#endif
- enable_timer();
- free_page(current->thread.temp_stack);
- set_cmdline("(kernel thread)");
- force_flush_all();
-
- current->thread.prev_sched = NULL;
- change_sig(SIGUSR1, 1);
- change_sig(SIGVTALRM, 1);
- change_sig(SIGPROF, 1);
- unblock_signals();
- if(!run_kernel_thread(fn, arg, &current->thread.jmp))
- do_exit(0);
-}
-
-static int new_thread_proc(void *stack)
-{
- change_sig(SIGIO, 0);
- change_sig(SIGVTALRM, 0);
- change_sig(SIGPROF, 0);
- init_new_thread(stack, new_thread_handler);
- os_usr1_process(os_getpid());
- return(0);
-}
-
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
struct task_struct *p;
current->thread.request.u.thread.proc = fn;
current->thread.request.u.thread.arg = arg;
- p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL);
+ p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL);
if(IS_ERR(p)) panic("do_fork failed in kernel_thread");
return(p->pid);
}
@@ -208,83 +125,13 @@ void set_current(void *t)
struct task_struct *task = t;
cpu_tasks[task->thread_info->cpu] = ((struct cpu_task)
- { task->thread.extern_pid, task });
+ { external_pid(task), task });
}
void *switch_to(void *prev, void *next, void *last)
{
- struct task_struct *from, *to;
- unsigned long flags;
- int vtalrm, alrm, prof, err, cpu;
- char c;
- /* jailing and SMP are incompatible, so this doesn't need to be
- * made per-cpu
- */
- static int reading;
-
- from = prev;
- to = next;
-
- to->thread.prev_sched = from;
-
- cpu = from->thread_info->cpu;
- if(cpu == 0)
- forward_interrupts(to->thread.extern_pid);
-#ifdef CONFIG_SMP
- forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.extern_pid);
-#endif
- local_irq_save(flags);
-
- vtalrm = change_sig(SIGVTALRM, 0);
- alrm = change_sig(SIGALRM, 0);
- prof = change_sig(SIGPROF, 0);
-
- forward_pending_sigio(to->thread.extern_pid);
-
- c = 0;
- set_current(to);
-
- reading = 0;
- err = os_write_file(to->thread.switch_pipe[1], &c, sizeof(c));
- if(err != sizeof(c))
- panic("write of switch_pipe failed, errno = %d", -err);
-
- reading = 1;
- if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
- os_kill_process(os_getpid());
-
- err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c));
- if(err != sizeof(c))
- panic("read of switch_pipe failed, errno = %d", -err);
-
- /* This works around a nasty race with 'jail'. If we are switching
- * between two threads of a threaded app and the incoming process
- * runs before the outgoing process reaches the read, and it makes
- * it all the way out to userspace, then it will have write-protected
- * the outgoing process stack. Then, when the outgoing process
- * returns from the write, it will segfault because it can no longer
- * write its own stack. So, in order to avoid that, the incoming
- * thread sits in a loop yielding until 'reading' is set. This
- * isn't entirely safe, since there may be a reschedule from a timer
- * happening between setting 'reading' and sleeping in read. But,
- * it should get a whole quantum in which to reach the read and sleep,
- * which should be enough.
- */
-
- if(jail){
- while(!reading) sched_yield();
- }
-
- change_sig(SIGVTALRM, vtalrm);
- change_sig(SIGALRM, alrm);
- change_sig(SIGPROF, prof);
-
- arch_switch();
-
- flush_tlb_all();
- local_irq_restore(flags);
-
- return(current->thread.prev_sched);
+ return(CHOOSE_MODE(switch_to_tt(prev, next),
+ switch_to_skas(prev, next)));
}
void interrupt_end(void)
@@ -295,193 +142,37 @@ void interrupt_end(void)
void release_thread(struct task_struct *task)
{
- os_kill_process(task->thread.extern_pid);
+ CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
}
-
+
void exit_thread(void)
{
- close(current->thread.switch_pipe[0]);
- close(current->thread.switch_pipe[1]);
+ CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
unprotect_stack((unsigned long) current->thread_info);
}
-
-/* Signal masking - signals are blocked at the start of fork_tramp. They
- * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
- * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
- * so it is blocked before it's called. They are re-enabled on sigreturn
- * despite the fact that they were blocked when the SIGUSR1 was issued because
- * copy_thread copies the parent's signcontext, including the signal mask
- * onto the signal frame.
- */
-
-void finish_fork_handler(int sig)
-{
- current->thread.regs.regs.sc = (void *) (&sig + 1);
- suspend_new_thread(current->thread.switch_pipe[0]);
-
-#ifdef CONFIG_SMP
- schedule_tail(NULL);
-#endif
- enable_timer();
- change_sig(SIGVTALRM, 1);
- force_flush_all();
- if(current->mm != current->parent->mm)
- protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
- task_protections((unsigned long) current->thread_info);
-
- current->thread.prev_sched = NULL;
-
- free_page(current->thread.temp_stack);
- change_sig(SIGUSR1, 0);
- set_user_mode(current);
-}
-
+
void *get_current(void)
{
return(current);
}
-/* This sigusr1 business works around a bug in gcc's -pg support.
- * Normally a procedure's mcount call comes after esp has been copied to
- * ebp and the new frame is constructed. With procedures with no locals,
- * the mcount comes before, as the first thing that the procedure does.
- * When that procedure is main for a thread, ebp comes in as NULL. So,
- * when mcount dereferences it, it segfaults. So, UML works around this
- * by adding a non-optimizable local to the various trampolines, fork_tramp
- * and outer_tramp below, and exec_tramp.
- */
-
-static int sigusr1 = SIGUSR1;
-
-int fork_tramp(void *stack)
-{
- int sig = sigusr1;
-
- change_sig(SIGIO, 0);
- change_sig(SIGVTALRM, 0);
- change_sig(SIGPROF, 0);
- init_new_thread(stack, finish_fork_handler);
-
- kill(os_getpid(), sig);
- return(0);
-}
-
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
{
- int new_pid, err;
- unsigned long stack;
- int (*tramp)(void *);
-
p->thread = (struct thread_struct) INIT_THREAD;
p->thread.kernel_stack =
(unsigned long) p->thread_info + 2 * PAGE_SIZE;
-
- if(current->thread.forking)
- tramp = fork_tramp;
- else {
- tramp = new_thread_proc;
- p->thread.request.u.thread = current->thread.request.u.thread;
- }
-
- err = os_pipe(p->thread.switch_pipe, 1, 1);
- if(err){
- printk("copy_thread : pipe failed, errno = %d\n", -err);
- return(err);
- }
-
- stack = alloc_stack(0, 0);
- if(stack == 0){
- printk(KERN_ERR "copy_thread : failed to allocate "
- "temporary stack\n");
- return(-ENOMEM);
- }
-
- clone_flags &= CLONE_VM;
- p->thread.temp_stack = stack;
- new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack,
- clone_flags, tramp);
- if(new_pid < 0){
- printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
- -new_pid);
- return(new_pid);
- }
-
- if(current->thread.forking){
- sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc);
- PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
- if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp;
- }
- p->thread.extern_pid = new_pid;
-
- current->thread.request.op = OP_FORK;
- current->thread.request.u.fork.pid = new_pid;
- os_usr1_process(os_getpid());
- return(0);
-}
-
-void tracing_reboot(void)
-{
- current->thread.request.op = OP_REBOOT;
- os_usr1_process(os_getpid());
+ return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
+ clone_flags, sp, stack_top, p, regs));
}
-void tracing_halt(void)
+void initial_thread_cb(void (*proc)(void *), void *arg)
{
- current->thread.request.op = OP_HALT;
- os_usr1_process(os_getpid());
+ CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
+ arg);
}
-
-void tracing_cb(void (*proc)(void *), void *arg)
-{
- if(os_getpid() == tracing_pid){
- (*proc)(arg);
- }
- else {
- current->thread.request.op = OP_CB;
- current->thread.request.u.cb.proc = proc;
- current->thread.request.u.cb.arg = arg;
- os_usr1_process(os_getpid());
- }
-}
-
-int do_proc_op(void *t, int proc_id)
-{
- struct task_struct *task;
- struct thread_struct *thread;
- int op, pid;
-
- task = t;
- thread = &task->thread;
- op = thread->request.op;
- switch(op){
- case OP_NONE:
- case OP_TRACE_ON:
- break;
- case OP_EXEC:
- pid = thread->request.u.exec.pid;
- do_exec(thread->extern_pid, pid);
- thread->extern_pid = pid;
- cpu_tasks[task->thread_info->cpu].pid = pid;
- break;
- case OP_FORK:
- attach_process(thread->request.u.fork.pid);
- break;
- case OP_CB:
- (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
- break;
- case OP_REBOOT:
- case OP_HALT:
- break;
- default:
- tracer_panic("Bad op in do_proc_op");
- break;
- }
- thread->request.op = OP_NONE;
- return(op);
-}
-
+
unsigned long stack_sp(unsigned long page)
{
return(page + PAGE_SIZE - sizeof(void *));
@@ -518,7 +209,7 @@ void default_idle(void)
void cpu_idle(void)
{
- default_idle();
+ CHOOSE_MODE(init_idle_tt(), init_idle_skas());
}
int page_size(void)
@@ -531,21 +222,25 @@ int page_mask(void)
return(PAGE_MASK);
}
-unsigned long um_virt_to_phys(void *t, unsigned long addr)
+void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
+ pte_t *pte_out)
{
- struct task_struct *task;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
- task = t;
- if(task->mm == NULL) return(0xffffffff);
+ if(task->mm == NULL)
+ return(ERR_PTR(-EINVAL));
pgd = pgd_offset(task->mm, addr);
pmd = pmd_offset(pgd, addr);
- if(!pmd_present(*pmd)) return(0xffffffff);
+ if(!pmd_present(*pmd))
+ return(ERR_PTR(-EINVAL));
pte = pte_offset_kernel(pmd, addr);
- if(!pte_present(*pte)) return(0xffffffff);
- return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
+ if(!pte_present(*pte))
+ return(ERR_PTR(-EINVAL));
+ if(pte_out != NULL)
+ *pte_out = *pte;
+ return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
}
char *current_cmd(void)
@@ -553,8 +248,8 @@ char *current_cmd(void)
#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
return("(Unknown)");
#else
- unsigned long addr = um_virt_to_phys(current, current->mm->arg_start);
- return addr == 0xffffffff? "(Unknown)": __va(addr);
+ void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
+ return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
#endif
}
@@ -602,22 +297,6 @@ unsigned long get_fault_addr(void)
EXPORT_SYMBOL(get_fault_addr);
-void clear_singlestep(void *t)
-{
- struct task_struct *task = (struct task_struct *) t;
-
- task->ptrace &= ~PT_DTRACE;
-}
-
-int singlestepping(void *t)
-{
- struct task_struct *task = (struct task_struct *) t;
-
- if(task->thread.singlestep_syscall)
- return(0);
- return(task->ptrace & PT_DTRACE);
-}
-
void not_implemented(void)
{
printk(KERN_DEBUG "Something isn't implemented in here\n");
@@ -631,6 +310,7 @@ int user_context(unsigned long sp)
}
extern void remove_umid_dir(void);
+
__uml_exitcall(remove_umid_dir);
extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -644,16 +324,6 @@ void do_uml_exitcalls(void)
(*call)();
}
-void *round_up(unsigned long addr)
-{
- return(ROUND_UP(addr));
-}
-
-void *round_down(unsigned long addr)
-{
- return(ROUND_DOWN(addr));
-}
-
char *uml_strdup(char *string)
{
char *new;
@@ -664,82 +334,6 @@ char *uml_strdup(char *string)
return(new);
}
-/* Changed by jail_setup, which is a setup */
-int jail = 0;
-
-int __init jail_setup(char *line, int *add)
-{
- int ok = 1;
-
- if(jail) return(0);
-#ifdef CONFIG_SMP
- printf("'jail' may not used used in a kernel with CONFIG_SMP "
- "enabled\n");
- ok = 0;
-#endif
-#ifdef CONFIG_HOSTFS
- printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
- "enabled\n");
- ok = 0;
-#endif
-#ifdef CONFIG_MODULES
- printf("'jail' may not used used in a kernel with CONFIG_MODULES "
- "enabled\n");
- ok = 0;
-#endif
- if(!ok) exit(1);
-
- /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
- * Removing it from the bounding set eliminates the ability of anything
- * to acquire it, and thus read or write kernel memory.
- */
- cap_lower(cap_bset, CAP_SYS_RAWIO);
- jail = 1;
- return(0);
-}
-
-__uml_setup("jail", jail_setup,
-"jail\n"
-" Enables the protection of kernel memory from processes.\n\n"
-);
-
-static void mprotect_kernel_mem(int w)
-{
- unsigned long start, end;
-
- if(!jail || (current == &init_task)) return;
-
- start = (unsigned long) current->thread_info + PAGE_SIZE;
- end = (unsigned long) current->thread_info + PAGE_SIZE * 4;
- protect(uml_reserved, start - uml_reserved, 1, w, 1, 1);
- protect(end, high_physmem - end, 1, w, 1, 1);
-
- start = (unsigned long) ROUND_DOWN(&_stext);
- end = (unsigned long) ROUND_UP(&_etext);
- protect(start, end - start, 1, w, 1, 1);
-
- start = (unsigned long) ROUND_DOWN(&_unprotected_end);
- end = (unsigned long) ROUND_UP(&_edata);
- protect(start, end - start, 1, w, 1, 1);
-
- start = (unsigned long) ROUND_DOWN(&__bss_start);
- end = (unsigned long) ROUND_UP(brk_start);
- protect(start, end - start, 1, w, 1, 1);
-
- mprotect_kernel_vm(w);
-}
-
-/* No SMP problems since jailing and SMP are incompatible */
-void unprotect_kernel_mem(void)
-{
- mprotect_kernel_mem(1);
-}
-
-void protect_kernel_mem(void)
-{
- mprotect_kernel_mem(0);
-}
-
void *get_init_task(void)
{
return(&init_thread_union.thread_info.task);
@@ -760,11 +354,6 @@ int clear_user_proc(void *buf, int size)
return(clear_user(buf, size));
}
-void set_thread_sc(void *sc)
-{
- current->thread.regs.regs.sc = sc;
-}
-
int smp_sigio_handler(void)
{
#ifdef CONFIG_SMP
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index d6dacf475c33..5a32974de6d8 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -9,6 +9,7 @@
#include "linux/smp_lock.h"
#include "linux/security.h"
#include "linux/ptrace.h"
+#include "linux/proc_mm.h"
#include "asm/ptrace.h"
#include "asm/uaccess.h"
#include "kern_util.h"
@@ -21,6 +22,11 @@ void ptrace_disable(struct task_struct *child)
{
}
+extern long do_mmap2(struct task_struct *task, unsigned long addr,
+ unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long fd,
+ unsigned long pgoff);
+
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -182,13 +188,13 @@ int sys_ptrace(long request, long pid, long addr, long data)
#ifdef PTRACE_GETREGS
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+ if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
FRAME_SIZE_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
- __put_user(getreg(child, i),(unsigned long *) data);
+ __put_user(getreg(child, i), (unsigned long *) data);
data += sizeof(long);
}
ret = 0;
@@ -232,6 +238,57 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = set_fpxregs(data, child);
break;
#endif
+ case PTRACE_FAULTINFO: {
+ struct ptrace_faultinfo fault;
+
+ fault = ((struct ptrace_faultinfo)
+ { .is_write = child->thread.err,
+ .addr = child->thread.cr2 });
+ ret = copy_to_user((unsigned long *) data, &fault,
+ sizeof(fault));
+ if(ret)
+ break;
+ break;
+ }
+ case PTRACE_SIGPENDING:
+ ret = copy_to_user((unsigned long *) data,
+ &child->pending.signal,
+ sizeof(child->pending.signal));
+ break;
+
+ case PTRACE_LDT: {
+ struct ptrace_ldt ldt;
+
+ if(copy_from_user(&ldt, (unsigned long *) data,
+ sizeof(ldt))){
+ ret = -EIO;
+ break;
+ }
+
+ /* This one is confusing, so just punt and return -EIO for
+ * now
+ */
+ ret = -EIO;
+ break;
+ }
+#ifdef CONFIG_PROC_MM
+ case PTRACE_SWITCH_MM: {
+ struct mm_struct *old = child->mm;
+ struct mm_struct *new = proc_mm_get_mm(data);
+
+ if(IS_ERR(new)){
+ ret = PTR_ERR(new);
+ break;
+ }
+
+ atomic_inc(&new->mm_users);
+ child->mm = new;
+ child->active_mm = new;
+ mmput(old);
+ ret = 0;
+ break;
+ }
+#endif
default:
ret = -EIO;
break;
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 41b1faec8140..61d7a4e6000f 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -8,6 +8,8 @@
#include "kern_util.h"
#include "kern.h"
#include "os.h"
+#include "mode.h"
+#include "choose-mode.h"
#ifdef CONFIG_SMP
static void kill_idlers(int me)
@@ -17,26 +19,17 @@ static void kill_idlers(int me)
for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
p = idle_threads[i];
- if((p != NULL) && (p->thread.extern_pid != me))
- os_kill_process(p->thread.extern_pid);
+ if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
+ os_kill_process(p->thread.mode.tt.extern_pid, 0);
}
}
#endif
static void kill_off_processes(void)
{
- struct task_struct *p;
- int me;
-
- me = os_getpid();
- for_each_process(p){
- if(p->thread.extern_pid != me)
- os_kill_process(p->thread.extern_pid);
- }
- if(init_task.thread.extern_pid != me)
- os_kill_process(init_task.thread.extern_pid);
+ CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
#ifdef CONFIG_SMP
- kill_idlers(me);
+ kill_idlers(os_getpid());
#endif
}
@@ -50,16 +43,14 @@ void machine_restart(char * __unused)
{
do_uml_exitcalls();
kill_off_processes();
- tracing_reboot();
- os_kill_process(os_getpid());
+ CHOOSE_MODE(reboot_tt(), reboot_skas());
}
void machine_power_off(void)
{
do_uml_exitcalls();
kill_off_processes();
- tracing_halt();
- os_kill_process(os_getpid());
+ CHOOSE_MODE(halt_tt(), halt_skas());
}
void machine_halt(void)
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
index 740608075b7c..da00ed4feede 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -39,14 +39,13 @@ struct openpty_arg {
int err;
};
-static int openpty_cb(void *arg)
+static void openpty_cb(void *arg)
{
struct openpty_arg *info = arg;
info->err = 0;
if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
info->err = errno;
- return(0);
}
void __init check_one_sigio(void (*proc)(int, int))
@@ -54,13 +53,9 @@ void __init check_one_sigio(void (*proc)(int, int))
struct sigaction old, new;
struct termios tt;
struct openpty_arg pty = { master : -1, slave : -1 };
- int master, slave, flags, err;
+ int master, slave, flags;
- err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2);
- if(err < 0){
- printk("run_helper_thread failed, errno = %d\n", -err);
- return;
- }
+ initial_thread_cb(openpty_cb, &pty);
if(pty.err){
printk("openpty failed, errno = %d\n", pty.err);
return;
@@ -387,7 +382,7 @@ void write_sigio_workaround(void)
goto out_close2;
write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
- CLONE_FILES, &stack, 0);
+ CLONE_FILES | CLONE_VM, &stack, 0);
if(write_sigio_pid < 0) goto out_close2;
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
index be60440cf012..f18ea0e1ac01 100644
--- a/arch/um/kernel/signal_kern.c
+++ b/arch/um/kernel/signal_kern.c
@@ -16,6 +16,7 @@
#include "linux/binfmts.h"
#include "asm/signal.h"
#include "asm/uaccess.h"
+#include "asm/unistd.h"
#include "user_util.h"
#include "kern_util.h"
#include "signal_kern.h"
@@ -23,6 +24,7 @@
#include "kern.h"
#include "frame_kern.h"
#include "sigcontext.h"
+#include "mode.h"
EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals);
@@ -69,6 +71,9 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
ret = 0;
switch(error){
+ case -ERESTART_RESTARTBLOCK:
+ current_thread_info()->restart_block.fn =
+ do_no_restart_syscall;
case -ERESTARTNOHAND:
ret = -EINTR;
break;
@@ -160,6 +165,10 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
PT_REGS_RESTART_SYSCALL(regs);
}
+ else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
+ PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
+ PT_REGS_RESTART_SYSCALL(regs);
+ }
}
/* This closes a way to execute a system call on the host. If
@@ -171,7 +180,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
*/
if((current->ptrace & PT_DTRACE) &&
is_syscall(PT_REGS_IP(&current->thread.regs)))
- current->thread.singlestep_syscall = 1;
+ (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0);
return(0);
}
@@ -228,6 +237,16 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
}
}
+static int copy_sc_from_user(struct pt_regs *to, void *from)
+{
+ int ret;
+
+ ret = CHOOSE_MODE(copy_sc_from_user_tt(to->regs.mode.tt, from,
+ &signal_frame_sc.arch),
+ copy_sc_from_user_skas(&to->regs, from));
+ return(ret);
+}
+
int sys_sigreturn(struct pt_regs regs)
{
void *sc = sp_to_sc(PT_REGS_SP(&regs));
@@ -241,8 +260,7 @@ int sys_sigreturn(struct pt_regs regs)
sigdelsetmask(&current->blocked, ~_BLOCKABLE);
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
- copy_sc_from_user(current->thread.regs.regs.sc, sc,
- &signal_frame_sc.arch);
+ copy_sc_from_user(&current->thread.regs, sc);
return(PT_REGS_SYSCALL_RET(&current->thread.regs));
}
@@ -257,8 +275,7 @@ int sys_rt_sigreturn(struct pt_regs regs)
sigdelsetmask(&current->blocked, ~_BLOCKABLE);
recalc_sigpending();
spin_unlock_irq(&current->sig->siglock);
- copy_sc_from_user(current->thread.regs.regs.sc, sc,
- &signal_frame_sc.arch);
+ copy_sc_from_user(&current->thread.regs, sc);
return(PT_REGS_SYSCALL_RET(&current->thread.regs));
}
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
index 2ef64a89e014..52cfd60a1433 100644
--- a/arch/um/kernel/signal_user.c
+++ b/arch/um/kernel/signal_user.c
@@ -21,13 +21,12 @@
void set_sigstack(void *sig_stack, int size)
{
- stack_t stack;
+ stack_t stack = ((stack_t) { .ss_flags = 0,
+ .ss_sp = (__ptr_t) sig_stack,
+ .ss_size = size - sizeof(void *) });
- stack.ss_sp = (__ptr_t) sig_stack;
- stack.ss_flags = 0;
- stack.ss_size = size - sizeof(void *);
if(sigaltstack(&stack, NULL) != 0)
- panic("sigaltstack failed");
+ panic("enabling signal stack failed, errno = %d\n", errno);
}
void set_handler(int sig, void (*handler)(int), int flags, ...)
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
new file mode 100644
index 000000000000..72c79956f6a6
--- /dev/null
+++ b/arch/um/kernel/skas/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \
+ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
+ sys-$(SUBARCH)/
+
+USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+include/skas_ptregs.h : util/mk_ptregs
+ util/mk_ptregs > $@
+
+util/mk_ptregs :
+ $(MAKE) -C util
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
+ $(MAKE) -C util clean
+ $(RM) -f include/skas_ptregs.h
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
new file mode 100644
index 000000000000..49356d26ac28
--- /dev/null
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "asm/current.h"
+#include "asm/page.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/mmu_context.h"
+#include "tlb.h"
+#include "skas.h"
+#include "mmu.h"
+#include "os.h"
+
+void flush_thread_skas(void)
+{
+ force_flush_all();
+ switch_mm_skas(current->mm->context.skas.mm_fd);
+}
+
+void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp)
+{
+ set_fs(USER_DS);
+ PT_REGS_IP(regs) = eip;
+ PT_REGS_SP(regs) = esp;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c
new file mode 100644
index 000000000000..c9942b6fc79b
--- /dev/null
+++ b/arch/um/kernel/skas/exec_user.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include "user.h"
+#include "kern_util.h"
+#include "os.h"
+#include "time_user.h"
+
+static int user_thread_tramp(void *arg)
+{
+ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+ panic("user_thread_tramp - PTRACE_TRACEME failed, "
+ "errno = %d\n", errno);
+ enable_timer();
+ os_stop_process(os_getpid());
+ return(0);
+}
+
+int user_thread(unsigned long stack, int flags)
+{
+ int pid, status;
+
+ pid = clone(user_thread_tramp, (void *) stack_sp(stack),
+ flags | CLONE_FILES | SIGCHLD, NULL);
+ if(pid < 0){
+ printk("user_thread - clone failed, errno = %d\n", errno);
+ return(pid);
+ }
+
+ if(waitpid(pid, &status, WUNTRACED) < 0){
+ printk("user_thread - waitpid failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
+ printk("user_thread - trampoline didn't stop, status = %d\n",
+ status);
+ return(-EINVAL);
+ }
+
+ return(pid);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/mmu.h b/arch/um/kernel/skas/include/mmu.h
new file mode 100644
index 000000000000..cfbc062bd9dc
--- /dev/null
+++ b/arch/um/kernel/skas/include/mmu.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MMU_H
+#define __SKAS_MMU_H
+
+#include "linux/list.h"
+#include "linux/spinlock.h"
+
+struct mmu_context_skas {
+ int mm_fd;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h
new file mode 100644
index 000000000000..09cadc99edc5
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_SKAS_H__
+#define __MODE_SKAS_H__
+
+extern unsigned long exec_regs[];
+extern unsigned long exec_fp_regs[];
+extern unsigned long exec_fpx_regs[];
+extern int have_fpx_regs;
+
+extern void user_time_init_skas(void);
+extern int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr);
+extern int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs,
+ unsigned long fault_addr, int fault_type);
+extern void sig_handler_common_skas(int sig, struct sigcontext *sc);
+extern void halt_skas(void);
+extern void reboot_skas(void);
+extern void kill_off_processes_skas(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h
new file mode 100644
index 000000000000..e4b472ac7d2d
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode_kern.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MODE_KERN_H__
+#define __SKAS_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+
+extern void flush_thread_skas(void);
+extern void *switch_to_skas(void *prev, void *next);
+extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp);
+extern int copy_thread_skas(int nr, unsigned long clone_flags,
+ unsigned long sp, unsigned long stack_top,
+ struct task_struct *p, struct pt_regs *regs);
+extern void release_thread_skas(struct task_struct *task);
+extern void exit_thread_skas(void);
+extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
+extern void init_idle_skas(void);
+extern void flush_tlb_kernel_vm_skas(void);
+extern void __flush_tlb_one_skas(unsigned long addr);
+extern void flush_tlb_range_skas(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+extern void flush_tlb_mm_skas(struct mm_struct *mm);
+extern void force_flush_all_skas(void);
+extern long execute_syscall_skas(void *r);
+extern void before_mem_skas(unsigned long unused);
+extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
+ unsigned long *task_size_out);
+extern int start_uml_skas(void);
+extern struct page *arch_validate_skas(struct page *page, int mask, int order);
+extern int external_pid_skas(struct task_struct *task);
+extern int thread_pid_skas(struct task_struct *task);
+
+#define kmem_end_skas (host_task_size)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h
new file mode 100644
index 000000000000..cce61a679052
--- /dev/null
+++ b/arch/um/kernel/skas/include/proc_mm.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_PROC_MM_H
+#define __SKAS_PROC_MM_H
+
+#define MM_MMAP 54
+#define MM_MUNMAP 55
+#define MM_MPROTECT 56
+#define MM_COPY_SEGMENTS 57
+
+struct mm_mmap {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+struct mm_munmap {
+ unsigned long addr;
+ unsigned long len;
+};
+
+struct mm_mprotect {
+ unsigned long addr;
+ unsigned long len;
+ unsigned int prot;
+};
+
+struct proc_mm_op {
+ int op;
+ union {
+ struct mm_mmap mmap;
+ struct mm_munmap munmap;
+ struct mm_mprotect mprotect;
+ int copy_segments;
+ } u;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h
new file mode 100644
index 000000000000..f4ab3fb43339
--- /dev/null
+++ b/arch/um/kernel/skas/include/ptrace-skas.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PTRACE_SKAS_H
+#define __PTRACE_SKAS_H
+
+#include "uml-config.h"
+
+#ifdef CONFIG_MODE_SKAS
+
+#include "skas_ptregs.h"
+
+#define HOST_FRAME_SIZE 17
+
+#define REGS_IP(r) ((r)[HOST_IP])
+#define REGS_SP(r) ((r)[HOST_SP])
+#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
+#define REGS_EAX(r) ((r)[HOST_EAX])
+#define REGS_EBX(r) ((r)[HOST_EBX])
+#define REGS_ECX(r) ((r)[HOST_ECX])
+#define REGS_EDX(r) ((r)[HOST_EDX])
+#define REGS_ESI(r) ((r)[HOST_ESI])
+#define REGS_EDI(r) ((r)[HOST_EDI])
+#define REGS_EBP(r) ((r)[HOST_EBP])
+#define REGS_CS(r) ((r)[HOST_CS])
+#define REGS_SS(r) ((r)[HOST_SS])
+#define REGS_DS(r) ((r)[HOST_DS])
+#define REGS_ES(r) ((r)[HOST_ES])
+#define REGS_FS(r) ((r)[HOST_FS])
+#define REGS_GS(r) ((r)[HOST_GS])
+
+#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
+
+#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
+
+#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
+
+#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
+
+#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
new file mode 100644
index 000000000000..e733b0c87448
--- /dev/null
+++ b/arch/um/kernel/skas/include/skas.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_H
+#define __SKAS_H
+
+#include "sysdep/ptrace.h"
+
+extern int userspace_pid;
+
+extern void switch_threads(void *me, void *next);
+extern void thread_wait(void *sw, void *fb);
+extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+ void (*handler)(int));
+extern int start_idle_thread(void *stack, void *switch_buf_ptr,
+ void **fork_buf_ptr);
+extern int user_thread(unsigned long stack, int flags);
+extern void userspace(struct uml_pt_regs *regs);
+extern void new_thread_proc(void *stack, void (*handler)(int sig));
+extern void remove_sigstack(void);
+extern void new_thread_handler(int sig);
+extern void handle_syscall(struct uml_pt_regs *regs);
+extern void map(int fd, unsigned long virt, unsigned long phys,
+ unsigned long len, int r, int w, int x);
+extern int unmap(int fd, void *addr, int len);
+extern int protect(int fd, unsigned long addr, unsigned long len,
+ int r, int w, int x, int must_succeed);
+extern void user_signal(int sig, struct uml_pt_regs *regs);
+extern int singlestepping_skas(void);
+extern int new_mm(int from);
+extern void save_registers(struct uml_pt_regs *regs);
+extern void restore_registers(struct uml_pt_regs *regs);
+extern void start_userspace(void);
+extern void init_registers(int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/skas_ptrace.h b/arch/um/kernel/skas/include/skas_ptrace.h
new file mode 100644
index 000000000000..7cd983d88d51
--- /dev/null
+++ b/arch/um/kernel/skas/include/skas_ptrace.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_PTRACE_H
+#define __SKAS_PTRACE_H
+
+struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+};
+
+struct ptrace_ldt {
+ int func;
+ void *ptr;
+ unsigned long bytecount;
+};
+
+#define PTRACE_FAULTINFO 52
+#define PTRACE_SIGPENDING 53
+#define PTRACE_LDT 54
+#define PTRACE_SWITCH_MM 55
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h
new file mode 100644
index 000000000000..df408e12d933
--- /dev/null
+++ b/arch/um/kernel/skas/include/uaccess.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_UACCESS_H
+#define __SKAS_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "linux/err.h"
+#include "asm/processor.h"
+#include "asm/pgtable.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+#include "kern_util.h"
+
+#define access_ok_skas(type, addr, size) \
+ ((segment_eq(get_fs(), KERNEL_DS)) || \
+ (((unsigned long) (addr) < TASK_SIZE) && \
+ ((unsigned long) (addr) + (size) < TASK_SIZE)))
+
+static inline int verify_area_skas(int type, const void * addr,
+ unsigned long size)
+{
+ return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
+ pte_t *pte_out);
+
+static inline unsigned long maybe_map(unsigned long virt, int is_write)
+{
+ pte_t pte;
+
+ void *phys = um_virt_to_phys(current, virt, &pte);
+ int dummy_code;
+
+ if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+ if(handle_page_fault(virt, 0, is_write, 0, &dummy_code))
+ return(0);
+ phys = um_virt_to_phys(current, virt, NULL);
+ }
+ return((unsigned long) __va((unsigned long) phys));
+}
+
+static inline int buffer_op(unsigned long addr, int len,
+ int (*op)(unsigned long addr, int len, void *arg),
+ void *arg)
+{
+ int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
+ int remain = len, n;
+
+ n = (*op)(addr, size, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+
+ addr += size;
+ remain -= size;
+ if(remain == 0)
+ return(0);
+
+ while(addr < ((addr + remain) & PAGE_MASK)){
+ n = (*op)(addr, PAGE_SIZE, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+
+ addr += PAGE_SIZE;
+ remain -= PAGE_SIZE;
+ }
+ if(remain == 0)
+ return(0);
+
+ n = (*op)(addr, remain, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+ return(0);
+}
+
+static inline int copy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+ unsigned long *to_ptr = arg, to = *to_ptr;
+
+ from = maybe_map(from, 0);
+ if(from == 0)
+ return(-1);
+
+ memcpy((void *) to, (void *) from, len);
+ *to_ptr += len;
+ return(0);
+}
+
+static inline int copy_from_user_skas(void *to, const void *from, int n)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memcpy(to, from, n);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_READ, from, n) ?
+ buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) :
+ n);
+}
+
+static inline int copy_chunk_to_user(unsigned long to, int len, void *arg)
+{
+ unsigned long *from_ptr = arg, from = *from_ptr;
+
+ to = maybe_map(to, 1);
+ if(to == 0)
+ return(-1);
+
+ memcpy((void *) to, (void *) from, len);
+ *from_ptr += len;
+ return(0);
+}
+
+static inline int copy_to_user_skas(void *to, const void *from, int n)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memcpy(to, from, n);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_WRITE, to, n) ?
+ buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) :
+ n);
+}
+
+static inline int strncpy_chunk_from_user(unsigned long from, int len,
+ void *arg)
+{
+ char **to_ptr = arg, *to = *to_ptr;
+ int n;
+
+ from = maybe_map(from, 0);
+ if(from == 0)
+ return(-1);
+
+ strncpy(to, (void *) from, len);
+ n = strnlen(to, len);
+ *to_ptr += n;
+
+ if(n < len)
+ return(1);
+ return(0);
+}
+
+static inline int strncpy_from_user_skas(char *dst, const char *src, int count)
+{
+ int n;
+ char *ptr = dst;
+
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ strncpy(dst, src, count);
+ return(strnlen(dst, count));
+ }
+
+ if(!access_ok_skas(VERIFY_READ, src, 1))
+ return(-EFAULT);
+
+ n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user,
+ &ptr);
+ if(n != 0)
+ return(-EFAULT);
+ return(strnlen(dst, count));
+}
+
+static inline int clear_chunk(unsigned long addr, int len, void *unused)
+{
+ addr = maybe_map(addr, 1);
+ if(addr == 0)
+ return(-1);
+
+ memset((void *) addr, 0, len);
+ return(0);
+}
+
+static inline int __clear_user_skas(void *mem, int len)
+{
+ return(buffer_op((unsigned long) mem, len, clear_chunk, NULL));
+}
+
+static inline int clear_user_skas(void *mem, int len)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memset(mem, 0, len);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+ buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len);
+}
+
+static inline int strnlen_chunk(unsigned long str, int len, void *arg)
+{
+ int *len_ptr = arg, n;
+
+ str = maybe_map(str, 0);
+ if(str == 0)
+ return(-1);
+
+ n = strnlen((void *) str, len);
+ *len_ptr += n;
+
+ if(n < len)
+ return(1);
+ return(0);
+}
+
+static inline int strnlen_user_skas(const void *str, int len)
+{
+ int count = 0, n;
+
+ if(segment_eq(get_fs(), KERNEL_DS))
+ return(strnlen(str, len) + 1);
+
+ n = buffer_op((unsigned long) str, len, strnlen_chunk, &count);
+ if(n == 0)
+ return(count + 1);
+ return(-EFAULT);
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
new file mode 100644
index 000000000000..0968b583473a
--- /dev/null
+++ b/arch/um/kernel/skas/mem.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "mem_user.h"
+
+unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
+ unsigned long *task_size_out)
+{
+ /* Round up to the nearest 4M */
+ unsigned long top = ROUND_4M((unsigned long) &arg);
+
+ *host_size_out = top;
+ *task_size_out = top;
+ return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
+}
+
+struct page *arch_validate_skas(struct page *page, int mask, int order)
+{
+ return(page);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
new file mode 100644
index 000000000000..7d12cdd621ae
--- /dev/null
+++ b/arch/um/kernel/skas/mem_user.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include "mem_user.h"
+#include "user.h"
+#include "os.h"
+#include "proc_mm.h"
+
+void map(int fd, unsigned long virt, unsigned long phys, unsigned long len,
+ int r, int w, int x)
+{
+ struct proc_mm_op map;
+ struct mem_region *region;
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+ region = phys_region(phys);
+
+ map = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = virt,
+ .len = len,
+ .prot = prot,
+ .flags = MAP_SHARED |
+ MAP_FIXED,
+ .fd = region->fd,
+ .offset = phys_offset(phys)
+ } } } );
+ n = os_write_file(fd, (char *) &map, sizeof(map));
+ if(n != sizeof(map))
+ printk("map : /proc/mm map failed, errno = %d\n", errno);
+}
+
+int unmap(int fd, void *addr, int len)
+{
+ struct proc_mm_op unmap;
+ int n;
+
+ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
+ .u =
+ { .munmap =
+ { .addr = (unsigned long) addr,
+ .len = len } } } );
+ n = os_write_file(fd, (char *) &unmap, sizeof(unmap));
+ if((n != 0) && (n != sizeof(unmap)))
+ return(-errno);
+ return(0);
+}
+
+int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
+ int x, int must_succeed)
+{
+ struct proc_mm_op protect;
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
+ .u =
+ { .mprotect =
+ { .addr = (unsigned long) addr,
+ .len = len,
+ .prot = prot } } } );
+
+ n = os_write_file(fd, (char *) &protect, sizeof(protect));
+ if((n != 0) && (n != sizeof(protect))){
+ if(must_succeed)
+ panic("protect failed, errno = %d", errno);
+ return(-errno);
+ }
+ return(0);
+}
+
+void before_mem_skas(unsigned long unused)
+{
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
new file mode 100644
index 000000000000..5911cdd0c0b7
--- /dev/null
+++ b/arch/um/kernel/skas/mmu.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/list.h"
+#include "linux/spinlock.h"
+#include "linux/slab.h"
+#include "asm/current.h"
+#include "asm/segment.h"
+#include "asm/mmu.h"
+#include "os.h"
+#include "skas.h"
+
+int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
+{
+ int from;
+
+ if((current->mm != NULL) && (current->mm != &init_mm))
+ from = current->mm->context.skas.mm_fd;
+ else from = -1;
+
+ mm->context.skas.mm_fd = new_mm(from);
+ if(mm->context.skas.mm_fd < 0)
+ panic("init_new_context_skas - new_mm failed, errno = %d\n",
+ mm->context.skas.mm_fd);
+
+ return(0);
+}
+
+void destroy_context_skas(struct mm_struct *mm)
+{
+ os_close_file(mm->context.skas.mm_fd);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 000000000000..15a1fd345178
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <asm/unistd.h>
+#include "user.h"
+#include "ptrace_user.h"
+#include "time_user.h"
+#include "sysdep/ptrace.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "skas.h"
+#include "skas_ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "os.h"
+#include "proc_mm.h"
+
+unsigned long exec_regs[FRAME_SIZE];
+unsigned long exec_fp_regs[HOST_FP_SIZE];
+unsigned long exec_fpx_regs[HOST_XFP_SIZE];
+int have_fpx_regs = 1;
+
+static void handle_segv(int pid)
+{
+ struct ptrace_faultinfo fault;
+ int err;
+
+ err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
+ if(err)
+ panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
+ errno);
+ segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
+}
+
+static void handle_trap(int pid, struct uml_pt_regs *regs)
+{
+ int err, syscall_nr, status;
+
+ syscall_nr = PT_SYSCALL_NR(regs->mode.skas.regs);
+ if(syscall_nr < 1){
+ relay_signal(SIGTRAP, regs);
+ return;
+ }
+ UPT_SYSCALL_NR(regs) = syscall_nr;
+
+ err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+ if(err < 0)
+ panic("handle_trap - nullifying syscall failed errno = %d\n",
+ errno);
+
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+ if(err < 0)
+ panic("handle_trap - continuing to end of syscall failed, "
+ "errno = %d\n", errno);
+
+ err = waitpid(pid, &status, WUNTRACED);
+ if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+ panic("handle_trap - failed to wait at end of syscall, "
+ "errno = %d, status = %d\n", errno, status);
+
+ handle_syscall(regs);
+}
+
+int userspace_pid;
+
+static int userspace_tramp(void *arg)
+{
+ init_new_thread_signals(0);
+ enable_timer();
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+ os_stop_process(os_getpid());
+}
+
+void start_userspace(void)
+{
+ void *stack;
+ unsigned long sp;
+ int pid, status, n;
+
+ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if(stack == MAP_FAILED)
+ panic("start_userspace : mmap failed, errno = %d", errno);
+ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+
+ pid = clone(userspace_tramp, (void *) sp,
+ CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
+ if(pid < 0)
+ panic("start_userspace : clone failed, errno = %d", errno);
+
+ do {
+ n = waitpid(pid, &status, WUNTRACED);
+ if(n < 0)
+ panic("start_userspace : wait failed, errno = %d",
+ errno);
+ } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
+
+ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
+ panic("start_userspace : expected SIGSTOP, got status = %d",
+ status);
+
+ if(munmap(stack, PAGE_SIZE) < 0)
+ panic("start_userspace : munmap failed, errno = %d\n", errno);
+
+ userspace_pid = pid;
+}
+
+void userspace(struct uml_pt_regs *regs)
+{
+ int err, status, op;
+
+ restore_registers(regs);
+
+ err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0);
+ if(err)
+ panic("userspace - PTRACE_SYSCALL failed, errno = %d\n",
+ errno);
+ while(1){
+ err = waitpid(userspace_pid, &status, WUNTRACED);
+ if(err < 0)
+ panic("userspace - waitpid failed, errno = %d\n",
+ errno);
+
+ regs->is_user = 1;
+ save_registers(regs);
+
+ if(WIFSTOPPED(status)){
+ switch(WSTOPSIG(status)){
+ case SIGSEGV:
+ handle_segv(userspace_pid);
+ break;
+ case SIGTRAP:
+ handle_trap(userspace_pid, regs);
+ break;
+ case SIGIO:
+ case SIGVTALRM:
+ case SIGILL:
+ case SIGBUS:
+ case SIGFPE:
+ user_signal(WSTOPSIG(status), regs);
+ break;
+ default:
+ printk("userspace - child stopped with signal "
+ "%d\n", WSTOPSIG(status));
+ }
+ interrupt_end();
+ }
+
+ restore_registers(regs);
+
+ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
+ PTRACE_SYSCALL;
+ err = ptrace(op, userspace_pid, 0, 0);
+ if(err)
+ panic("userspace - PTRACE_SYSCALL failed, "
+ "errno = %d\n", errno);
+ }
+}
+
+void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+ void (*handler)(int))
+{
+ jmp_buf switch_buf, fork_buf;
+
+ *switch_buf_ptr = &switch_buf;
+ *fork_buf_ptr = &fork_buf;
+
+ if(setjmp(fork_buf) == 0)
+ new_thread_proc(stack, handler);
+
+ remove_sigstack();
+}
+
+void thread_wait(void *sw, void *fb)
+{
+ jmp_buf buf, **switch_buf = sw, *fork_buf;
+
+ *switch_buf = &buf;
+ fork_buf = fb;
+ if(setjmp(buf) == 0)
+ longjmp(*fork_buf, 1);
+}
+
+static int move_registers(int int_op, int fp_op, struct uml_pt_regs *regs,
+ unsigned long *fp_regs)
+{
+ if(ptrace(int_op, userspace_pid, 0, regs->mode.skas.regs) < 0)
+ return(-errno);
+ if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0)
+ return(-errno);
+ return(0);
+}
+
+void save_registers(struct uml_pt_regs *regs)
+{
+ unsigned long *fp_regs;
+ int err, fp_op;
+
+ if(have_fpx_regs){
+ fp_op = PTRACE_GETFPXREGS;
+ fp_regs = regs->mode.skas.xfp;
+ }
+ else {
+ fp_op = PTRACE_GETFPREGS;
+ fp_regs = regs->mode.skas.fp;
+ }
+
+ err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs);
+ if(err)
+ panic("save_registers - saving registers failed, errno = %d\n",
+ err);
+}
+
+void restore_registers(struct uml_pt_regs *regs)
+{
+ unsigned long *fp_regs;
+ int err, fp_op;
+
+ if(have_fpx_regs){
+ fp_op = PTRACE_SETFPXREGS;
+ fp_regs = regs->mode.skas.xfp;
+ }
+ else {
+ fp_op = PTRACE_SETFPREGS;
+ fp_regs = regs->mode.skas.fp;
+ }
+
+ err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs);
+ if(err)
+ panic("restore_registers - saving registers failed, "
+ "errno = %d\n", err);
+}
+
+void switch_threads(void *me, void *next)
+{
+ jmp_buf my_buf, **me_ptr = me, *next_buf = next;
+
+ *me_ptr = &my_buf;
+ if(setjmp(my_buf) == 0)
+ longjmp(*next_buf, 1);
+}
+
+static jmp_buf initial_jmpbuf;
+
+/* XXX Make these percpu */
+static void (*cb_proc)(void *arg);
+static void *cb_arg;
+static jmp_buf *cb_back;
+
+int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+{
+ jmp_buf **switch_buf = switch_buf_ptr;
+ int n;
+
+ *fork_buf_ptr = &initial_jmpbuf;
+ n = setjmp(initial_jmpbuf);
+ if(n == 0)
+ new_thread_proc((void *) stack, new_thread_handler);
+ else if(n == 1)
+ remove_sigstack();
+ else if(n == 2){
+ (*cb_proc)(cb_arg);
+ longjmp(*cb_back, 1);
+ }
+ else if(n == 3)
+ return(0);
+ else if(n == 4)
+ return(1);
+ longjmp(**switch_buf, 1);
+}
+
+void remove_sigstack(void)
+{
+ stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
+ .ss_sp = NULL,
+ .ss_size = 0 });
+
+ if(sigaltstack(&stack, NULL) != 0)
+ panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void initial_thread_cb_skas(void (*proc)(void *), void *arg)
+{
+ jmp_buf here;
+
+ cb_proc = proc;
+ cb_arg = arg;
+ cb_back = &here;
+ if(setjmp(here) == 0)
+ longjmp(initial_jmpbuf, 2);
+
+ cb_proc = NULL;
+ cb_arg = NULL;
+ cb_back = NULL;
+}
+
+void halt_skas(void)
+{
+ block_signals();
+ longjmp(initial_jmpbuf, 3);
+}
+
+void reboot_skas(void)
+{
+ block_signals();
+ longjmp(initial_jmpbuf, 4);
+}
+
+int new_mm(int from)
+{
+ struct proc_mm_op copy;
+ int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
+
+ if(fd < 0)
+ return(-errno);
+
+ if(from != -1){
+ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
+ .u =
+ { .copy_segments = from } } );
+ n = os_write_file(fd, (char *) &copy, sizeof(copy));
+ if(n != sizeof(copy))
+ printk("new_mm : /proc/mm copy_segments failed, "
+ "errno = %d\n", errno);
+ }
+ return(fd);
+}
+
+void switch_mm_skas(int mm_fd)
+{
+ int err;
+
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd);
+ if(err)
+ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
+ errno);
+}
+
+void kill_off_processes_skas(void)
+{
+ os_kill_process(userspace_pid, 1);
+}
+
+void init_registers(int pid)
+{
+ int err;
+
+ if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0)
+ panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
+ errno);
+
+ err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
+ if(!err)
+ return;
+
+ have_fpx_regs = 0;
+ if(errno != EIO)
+ panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
+ errno);
+
+ err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
+ if(err)
+ panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
+ errno);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
new file mode 100644
index 000000000000..ed17599d2c56
--- /dev/null
+++ b/arch/um/kernel/skas/process_kern.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "kern_util.h"
+#include "time_user.h"
+#include "signal_user.h"
+#include "skas.h"
+#include "os.h"
+#include "user_util.h"
+#include "tlb.h"
+#include "frame.h"
+#include "kern.h"
+#include "mode.h"
+
+int singlestepping_skas(void)
+{
+ int ret = current->ptrace & PT_DTRACE;
+
+ current->ptrace &= ~PT_DTRACE;
+ return(ret);
+}
+
+void *switch_to_skas(void *prev, void *next)
+{
+ struct task_struct *from, *to;
+
+ from = prev;
+ to = next;
+
+ /* XXX need to check runqueues[cpu].idle */
+ if(current->pid == 0)
+ switch_timers(0);
+
+ to->thread.prev_sched = from;
+ set_current(to);
+
+ switch_threads(&from->thread.mode.skas.switch_buf,
+ to->thread.mode.skas.switch_buf);
+
+ if(current->pid == 0)
+ switch_timers(1);
+
+ return(current->thread.prev_sched);
+}
+
+extern void schedule_tail(struct task_struct *prev);
+
+void new_thread_handler(int sig)
+{
+ int (*fn)(void *), n;
+ void *arg;
+
+ fn = current->thread.request.u.thread.proc;
+ arg = current->thread.request.u.thread.arg;
+ change_sig(SIGUSR1, 1);
+ thread_wait(&current->thread.mode.skas.switch_buf,
+ current->thread.mode.skas.fork_buf);
+
+#ifdef CONFIG_SMP
+ schedule_tail(NULL);
+#endif
+ current->thread.prev_sched = NULL;
+
+ n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
+ if(n == 1)
+ userspace(&current->thread.regs.regs);
+ else if(n == 2)
+ do_exit(0);
+}
+
+void new_thread_proc(void *stack, void (*handler)(int sig))
+{
+ init_new_thread_stack(stack, handler);
+ os_usr1_process(os_getpid());
+}
+
+void release_thread_skas(struct task_struct *task)
+{
+}
+
+void exit_thread_skas(void)
+{
+}
+
+void fork_handler(int sig)
+{
+ change_sig(SIGUSR1, 1);
+ thread_wait(&current->thread.mode.skas.switch_buf,
+ current->thread.mode.skas.fork_buf);
+
+ force_flush_all();
+#ifdef CONFIG_SMP
+ schedule_tail(current->thread.prev_sched);
+#endif
+ current->thread.prev_sched = NULL;
+ unblock_signals();
+
+ userspace(&current->thread.regs.regs);
+}
+
+int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
+ unsigned long stack_top, struct task_struct * p,
+ struct pt_regs *regs)
+{
+ void (*handler)(int);
+
+ if(current->thread.forking){
+ memcpy(&p->thread.regs.regs.mode.skas,
+ &current->thread.regs.regs.mode.skas,
+ sizeof(p->thread.regs.regs.mode.skas));
+ REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.skas.regs, 0);
+ if(sp != 0) REGS_SP(p->thread.regs.regs.mode.skas.regs) = sp;
+
+ handler = fork_handler;
+ }
+ else {
+ memcpy(p->thread.regs.regs.mode.skas.regs, exec_regs,
+ sizeof(p->thread.regs.regs.mode.skas.regs));
+ memcpy(p->thread.regs.regs.mode.skas.fp, exec_fp_regs,
+ sizeof(p->thread.regs.regs.mode.skas.fp));
+ memcpy(p->thread.regs.regs.mode.skas.xfp, exec_fpx_regs,
+ sizeof(p->thread.regs.regs.mode.skas.xfp));
+ p->thread.request.u.thread = current->thread.request.u.thread;
+ handler = new_thread_handler;
+ }
+
+ new_thread((void *) p->thread.kernel_stack,
+ &p->thread.mode.skas.switch_buf,
+ &p->thread.mode.skas.fork_buf, handler);
+ return(0);
+}
+
+void init_idle_skas(void)
+{
+ cpu_tasks[current->thread_info->cpu].pid = os_getpid();
+ default_idle();
+}
+
+extern void start_kernel(void);
+
+static int start_kernel_proc(void *unused)
+{
+ int pid;
+
+ block_signals();
+ pid = os_getpid();
+
+ cpu_tasks[0].pid = pid;
+ cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ cpu_online_map = 1;
+#endif
+ start_kernel();
+ return(0);
+}
+
+int start_uml_skas(void)
+{
+ start_userspace();
+ capture_signal_stack();
+
+ init_new_thread_signals(1);
+ idle_timer();
+
+ init_task.thread.request.u.thread.proc = start_kernel_proc;
+ init_task.thread.request.u.thread.arg = NULL;
+ return(start_idle_thread((void *) init_task.thread.kernel_stack,
+ &init_task.thread.mode.skas.switch_buf,
+ &init_task.thread.mode.skas.fork_buf));
+}
+
+int external_pid_skas(struct task_struct *task)
+{
+ return(userspace_pid);
+}
+
+int thread_pid_skas(struct task_struct *task)
+{
+ return(userspace_pid);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile
new file mode 100644
index 000000000000..2ad8271c604d
--- /dev/null
+++ b/arch/um/kernel/skas/sys-i386/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = sigcontext.o
+
+USER_OBJS = sigcontext.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
diff --git a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c
new file mode 100644
index 000000000000..07bb0ea0ed8a
--- /dev/null
+++ b/arch/um/kernel/skas/sys-i386/sigcontext.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <asm/sigcontext.h>
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include "sysdep/ptrace.h"
+#include "sysdep/ptrace_user.h"
+#include "kern_util.h"
+#include "user.h"
+#include "sigcontext.h"
+
+extern int userspace_pid;
+
+int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr)
+{
+ struct sigcontext sc, *from = from_ptr;
+ unsigned long fpregs[FP_FRAME_SIZE];
+ int err;
+
+ err = copy_from_user_proc(&sc, from, sizeof(sc));
+ err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs));
+ if(err)
+ return(err);
+
+ regs->mode.skas.regs[GS] = sc.gs;
+ regs->mode.skas.regs[FS] = sc.fs;
+ regs->mode.skas.regs[ES] = sc.es;
+ regs->mode.skas.regs[DS] = sc.ds;
+ regs->mode.skas.regs[EDI] = sc.edi;
+ regs->mode.skas.regs[ESI] = sc.esi;
+ regs->mode.skas.regs[EBP] = sc.ebp;
+ regs->mode.skas.regs[UESP] = sc.esp;
+ regs->mode.skas.regs[EBX] = sc.ebx;
+ regs->mode.skas.regs[EDX] = sc.edx;
+ regs->mode.skas.regs[ECX] = sc.ecx;
+ regs->mode.skas.regs[EAX] = sc.eax;
+ regs->mode.skas.regs[EIP] = sc.eip;
+ regs->mode.skas.regs[CS] = sc.cs;
+ regs->mode.skas.regs[EFL] = sc.eflags;
+ regs->mode.skas.regs[UESP] = sc.esp_at_signal;
+ regs->mode.skas.regs[SS] = sc.ss;
+ regs->mode.skas.fault_addr = sc.cr2;
+ regs->mode.skas.fault_type = FAULT_WRITE(sc.err);
+ regs->mode.skas.trap_type = sc.trapno;
+
+ err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs);
+ if(err < 0){
+ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
+ "errno = %d\n", errno);
+ return(1);
+ }
+
+ return(0);
+}
+
+int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs,
+ unsigned long fault_addr, int fault_type)
+{
+ struct sigcontext sc, *to = to_ptr;
+ struct _fpstate *to_fp;
+ unsigned long fpregs[FP_FRAME_SIZE];
+ int err;
+
+ sc.gs = regs->mode.skas.regs[GS];
+ sc.fs = regs->mode.skas.regs[FS];
+ sc.es = regs->mode.skas.regs[ES];
+ sc.ds = regs->mode.skas.regs[DS];
+ sc.edi = regs->mode.skas.regs[EDI];
+ sc.esi = regs->mode.skas.regs[ESI];
+ sc.ebp = regs->mode.skas.regs[EBP];
+ sc.esp = regs->mode.skas.regs[UESP];
+ sc.ebx = regs->mode.skas.regs[EBX];
+ sc.edx = regs->mode.skas.regs[EDX];
+ sc.ecx = regs->mode.skas.regs[ECX];
+ sc.eax = regs->mode.skas.regs[EAX];
+ sc.eip = regs->mode.skas.regs[EIP];
+ sc.cs = regs->mode.skas.regs[CS];
+ sc.eflags = regs->mode.skas.regs[EFL];
+ sc.esp_at_signal = regs->mode.skas.regs[UESP];
+ sc.ss = regs->mode.skas.regs[SS];
+ sc.cr2 = fault_addr;
+ sc.err = TO_SC_ERR(fault_type);
+ sc.trapno = regs->mode.skas.trap_type;
+
+ err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs);
+ if(err < 0){
+ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, "
+ "errno = %d\n", errno);
+ return(1);
+ }
+ to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
+ sc.fpstate = to_fp;
+
+ if(err)
+ return(err);
+
+ return(copy_to_user_proc(to, &sc, sizeof(sc)) ||
+ copy_to_user_proc(to_fp, fpregs, sizeof(fpregs)));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
new file mode 100644
index 000000000000..d870870db1ac
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_kern.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sys.h"
+#include "asm/errno.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/current.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall_skas(void *r)
+{
+ struct pt_regs *regs = r;
+ long res;
+ int syscall;
+
+ current->thread.nsyscalls++;
+ nsyscalls++;
+ syscall = regs->regs.syscall;
+
+ if((syscall >= NR_syscalls) || (syscall < 0))
+ res = -ENOSYS;
+ else res = EXECUTE_SYSCALL(syscall, regs);
+
+ return(res);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
new file mode 100644
index 000000000000..4f43f5492163
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include "kern_util.h"
+#include "syscall_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+
+/* XXX Bogus */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514
+
+void handle_syscall(struct uml_pt_regs *regs)
+{
+ long result;
+ int index;
+
+ host_to_regs(regs);
+ index = record_syscall_start(UPT_SYSCALL_NR(regs));
+
+ syscall_trace();
+ result = execute_syscall(regs);
+
+ REGS_SET_SYSCALL_RETURN(regs->mode.skas.regs, result);
+ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
+ (result == -ERESTARTNOINTR))
+ do_signal(result);
+
+ syscall_trace();
+ record_syscall_end(index, result);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
new file mode 100644
index 000000000000..98091494b897
--- /dev/null
+++ b/arch/um/kernel/skas/time.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <sys/signal.h>
+#include <sys/time.h>
+#include "time_user.h"
+#include "process.h"
+#include "user.h"
+
+void user_time_init_skas(void)
+{
+ if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+ panic("Couldn't set SIGALRM handler");
+ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+ panic("Couldn't set SIGVTALRM handler");
+ set_interval(ITIMER_VIRTUAL);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
new file mode 100644
index 000000000000..655d3cdee856
--- /dev/null
+++ b/arch/um/kernel/skas/tlb.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/mmu.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "skas.h"
+#include "os.h"
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+ unsigned long end_addr, int force)
+{
+ pgd_t *npgd;
+ pmd_t *npmd;
+ pte_t *npte;
+ unsigned long addr;
+ int r, w, x, err, fd;
+
+ if(mm == NULL) return;
+ fd = mm->context.skas.mm_fd;
+ for(addr = start_addr; addr < end_addr;){
+ npgd = pgd_offset(mm, addr);
+ npmd = pmd_offset(npgd, addr);
+ if(pmd_present(*npmd)){
+ npte = pte_offset_kernel(npmd, addr);
+ r = pte_read(*npte);
+ w = pte_write(*npte);
+ x = pte_exec(*npte);
+ if(!pte_dirty(*npte)) w = 0;
+ if(!pte_young(*npte)){
+ r = 0;
+ w = 0;
+ }
+ if(force || pte_newpage(*npte)){
+ err = unmap(fd, (void *) addr, PAGE_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ if(pte_present(*npte))
+ map(fd, addr,
+ pte_val(*npte) & PAGE_MASK,
+ PAGE_SIZE, r, w, x);
+ }
+ else if(pte_newprot(*npte)){
+ protect(fd, addr, PAGE_SIZE, r, w, x, 1);
+ }
+ *npte = pte_mkuptodate(*npte);
+ addr += PAGE_SIZE;
+ }
+ else {
+ if(force || pmd_newpage(*npmd)){
+ err = unmap(fd, (void *) addr, PMD_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ pmd_mkuptodate(*npmd);
+ }
+ addr += PMD_SIZE;
+ }
+ }
+}
+
+static void flush_kernel_vm_range(unsigned long start, unsigned long end)
+{
+ struct mm_struct *mm;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr;
+ int updated = 0, err;
+
+ mm = &init_mm;
+ for(addr = start_vm; addr < end_vm;){
+ pgd = pgd_offset(mm, addr);
+ pmd = pmd_offset(pgd, addr);
+ if(pmd_present(*pmd)){
+ pte = pte_offset_kernel(pmd, addr);
+ if(!pte_present(*pte) || pte_newpage(*pte)){
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ PAGE_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ if(pte_present(*pte))
+ map_memory(addr,
+ pte_val(*pte) & PAGE_MASK,
+ PAGE_SIZE, 1, 1, 1);
+ }
+ else if(pte_newprot(*pte)){
+ updated = 1;
+ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
+ }
+ addr += PAGE_SIZE;
+
+ }
+ else {
+ if(pmd_newpage(*pmd)){
+ updated = 1;
+ err = os_unmap_memory((void *) addr, PMD_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr += PMD_SIZE;
+ }
+ }
+}
+
+void flush_tlb_kernel_vm_skas(void)
+{
+ flush_kernel_vm_range(start_vm, end_vm);
+}
+
+void __flush_tlb_one_skas(unsigned long addr)
+{
+ flush_kernel_vm_range(addr, addr + PAGE_SIZE);
+}
+
+void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ if(vma->vm_mm == NULL)
+ flush_kernel_vm_range(start, end);
+ else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm_skas(struct mm_struct *mm)
+{
+ if(mm == NULL)
+ flush_tlb_kernel_vm_skas();
+ else fix_range(mm, 0, host_task_size, 0);
+}
+
+void force_flush_all_skas(void)
+{
+ fix_range(current->mm, 0, host_task_size, 1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
new file mode 100644
index 000000000000..e906e5a630cb
--- /dev/null
+++ b/arch/um/kernel/skas/trap_user.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <errno.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "sigcontext.h"
+
+void sig_handler_common_skas(int sig, struct sigcontext *sc)
+{
+ struct uml_pt_regs save_regs, *r;
+ struct signal_info *info;
+ int save_errno = errno;
+
+ r = (struct uml_pt_regs *) TASK_REGS(get_current());
+ save_regs = *r;
+ r->is_user = 0;
+ r->mode.skas.fault_addr = SC_FAULT_ADDR(sc);
+ r->mode.skas.fault_type = SC_FAULT_TYPE(sc);
+ r->mode.skas.trap_type = SC_TRAP_TYPE(sc);
+
+ change_sig(SIGUSR1, 1);
+ info = &sig_info[sig];
+ if(!info->is_irq) unblock_signals();
+
+ (*info->handler)(sig, r);
+
+ *r = save_regs;
+ errno = save_errno;
+}
+
+extern int missed_ticks[];
+
+void user_signal(int sig, struct uml_pt_regs *regs)
+{
+ struct signal_info *info;
+
+ if(sig == SIGVTALRM)
+ missed_ticks[cpu()]++;
+ regs->is_user = 1;
+ regs->mode.skas.fault_addr = 0;
+ regs->mode.skas.fault_type = 0;
+ regs->mode.skas.trap_type = 0;
+ info = &sig_info[sig];
+ (*info->handler)(sig, regs);
+
+ unblock_signals();
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
new file mode 100644
index 000000000000..e62dc253e895
--- /dev/null
+++ b/arch/um/kernel/skas/util/Makefile
@@ -0,0 +1,10 @@
+all: mk_ptregs
+
+mk_ptregs : mk_ptregs.o
+ $(CC) -o mk_ptregs mk_ptregs.o
+
+mk_ptregs.o : mk_ptregs.c
+ $(CC) -c $<
+
+clean :
+ $(RM) -f mk_ptregs *.o *~
diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c
new file mode 100644
index 000000000000..658791017373
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs.c
@@ -0,0 +1,50 @@
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
+
+int main(int argc, char **argv)
+{
+ printf("/* Automatically generated by "
+ "arch/um/kernel/skas/util/mk_ptregs */\n");
+ printf("\n");
+ printf("#ifndef __SKAS_PT_REGS_\n");
+ printf("#define __SKAS_PT_REGS_\n");
+ printf("\n");
+ printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
+ printf("#define HOST_FP_SIZE %d\n",
+ sizeof(struct user_i387_struct) / sizeof(unsigned long));
+ printf("#define HOST_XFP_SIZE %d\n",
+ sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
+
+ PRINT_REG("IP", EIP);
+ PRINT_REG("SP", UESP);
+ PRINT_REG("EFLAGS", EFL);
+ PRINT_REG("EAX", EAX);
+ PRINT_REG("EBX", EBX);
+ PRINT_REG("ECX", ECX);
+ PRINT_REG("EDX", EDX);
+ PRINT_REG("ESI", ESI);
+ PRINT_REG("EDI", EDI);
+ PRINT_REG("EBP", EBP);
+ PRINT_REG("CS", CS);
+ PRINT_REG("SS", SS);
+ PRINT_REG("DS", DS);
+ PRINT_REG("FS", FS);
+ PRINT_REG("ES", ES);
+ PRINT_REG("GS", GS);
+ printf("\n");
+ printf("#endif\n");
+ return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index c9d9b15789d1..3503ed13f59a 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -116,7 +116,8 @@ static int idle_proc(void *cpup)
panic("CPU#%d failed to create IPI pipe, errno = %d", cpu,
-err);
- activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid);
+ activate_ipi(cpu_data[cpu].ipi_pipe[0],
+ current->thread.mode.tt.extern_pid);
wmb();
if (test_and_set_bit(cpu, &smp_callin_map)) {
@@ -143,10 +144,12 @@ static struct task_struct *idle_thread(int cpu)
if(IS_ERR(new_task)) panic("do_fork failed in idle_thread");
cpu_tasks[cpu] = ((struct cpu_task)
- { .pid = new_task->thread.extern_pid,
+ { .pid = new_task->thread.mode.tt.extern_pid,
.task = new_task } );
idle_threads[cpu] = new_task;
- write(new_task->thread.switch_pipe[1], &c, sizeof(c));
+ CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c,
+ sizeof(c)),
+ ({ panic("skas mode doesn't support SMP"); }));
return(new_task);
}
@@ -162,7 +165,8 @@ void smp_prepare_cpus(unsigned int maxcpus)
err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
- activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid);
+ activate_ipi(cpu_data[0].ipi_pipe[0],
+ current->thread.mode.tt.extern_pid);
for(cpu = 1; cpu < ncpus; cpu++){
printk("Booting processor %d...\n", cpu);
diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
index f76c35dc568b..f54c2ae723b5 100644
--- a/arch/um/kernel/sys_call_table.c
+++ b/arch/um/kernel/sys_call_table.c
@@ -8,10 +8,12 @@
#include "linux/version.h"
#include "linux/sys.h"
#include "linux/swap.h"
+#include "linux/sysctl.h"
#include "asm/signal.h"
#include "sysdep/syscalls.h"
#include "kern_util.h"
+extern syscall_handler_t sys_restart_syscall;
extern syscall_handler_t sys_ni_syscall;
extern syscall_handler_t sys_exit;
extern syscall_handler_t sys_fork;
@@ -125,10 +127,8 @@ extern syscall_handler_t sys_ni_syscall;
extern syscall_handler_t sys_adjtimex;
extern syscall_handler_t sys_mprotect;
extern syscall_handler_t sys_sigprocmask;
-extern syscall_handler_t sys_create_module;
extern syscall_handler_t sys_init_module;
extern syscall_handler_t sys_delete_module;
-extern syscall_handler_t sys_get_kernel_syms;
extern syscall_handler_t sys_quotactl;
extern syscall_handler_t sys_getpgid;
extern syscall_handler_t sys_fchdir;
@@ -162,7 +162,6 @@ extern syscall_handler_t sys_mremap;
extern syscall_handler_t sys_setresuid16;
extern syscall_handler_t sys_getresuid16;
extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_query_module;
extern syscall_handler_t sys_poll;
extern syscall_handler_t sys_nfsservctl;
extern syscall_handler_t sys_setresgid16;
@@ -235,9 +234,10 @@ extern syscall_handler_t sys_epoll_create;
extern syscall_handler_t sys_epoll_ctl;
extern syscall_handler_t sys_epoll_wait;
extern syscall_handler_t sys_remap_file_pages;
+extern syscall_handler_t sys_set_tid_address;
#if CONFIG_NFSD
-#define NFSSERVCTL sys_nfsserctl
+#define NFSSERVCTL sys_nfsservctl
#else
#define NFSSERVCTL sys_ni_syscall
#endif
@@ -246,7 +246,7 @@ extern syscall_handler_t um_mount;
extern syscall_handler_t um_time;
extern syscall_handler_t um_stime;
-#define LAST_GENERIC_SYSCALL __NR_remap_file_pages
+#define LAST_GENERIC_SYSCALL __NR_set_tid_address
#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
#define LAST_SYSCALL LAST_GENERIC_SYSCALL
@@ -255,7 +255,7 @@ extern syscall_handler_t um_stime;
#endif
syscall_handler_t *sys_call_table[] = {
- [ 0 ] = sys_ni_syscall,
+ [ __NR_restart_syscall ] = sys_restart_syscall,
[ __NR_exit ] = sys_exit,
[ __NR_fork ] = sys_fork,
[ __NR_read ] = (syscall_handler_t *) sys_read,
@@ -384,10 +384,10 @@ syscall_handler_t *sys_call_table[] = {
[ __NR_adjtimex ] = sys_adjtimex,
[ __NR_mprotect ] = sys_mprotect,
[ __NR_sigprocmask ] = sys_sigprocmask,
- [ __NR_create_module ] = sys_create_module,
+ [ __NR_create_module ] = sys_ni_syscall,
[ __NR_init_module ] = sys_init_module,
[ __NR_delete_module ] = sys_delete_module,
- [ __NR_get_kernel_syms ] = sys_get_kernel_syms,
+ [ __NR_get_kernel_syms ] = sys_ni_syscall,
[ __NR_quotactl ] = sys_quotactl,
[ __NR_getpgid ] = sys_getpgid,
[ __NR_fchdir ] = sys_fchdir,
@@ -424,7 +424,7 @@ syscall_handler_t *sys_call_table[] = {
[ __NR_setresuid ] = sys_setresuid16,
[ __NR_getresuid ] = sys_getresuid16,
[ __NR_vm86 ] = sys_ni_syscall,
- [ __NR_query_module ] = sys_query_module,
+ [ __NR_query_module ] = sys_ni_syscall,
[ __NR_poll ] = sys_poll,
[ __NR_nfsservctl ] = NFSSERVCTL,
[ __NR_setresgid ] = sys_setresgid16,
@@ -489,6 +489,7 @@ syscall_handler_t *sys_call_table[] = {
[ __NR_epoll_ctl ] = sys_epoll_ctl,
[ __NR_epoll_wait ] = sys_epoll_wait,
[ __NR_remap_file_pages ] = sys_remap_file_pages,
+ [ __NR_set_tid_address ] = sys_set_tid_address,
ARCH_SYSCALLS
[ LAST_SYSCALL + 1 ... NR_syscalls ] =
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
index b15340a6b837..bcebea22c940 100644
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -20,6 +20,11 @@
#include "kern_util.h"
#include "user_util.h"
#include "sysdep/syscalls.h"
+#include "mode_kern.h"
+#include "choose-mode.h"
+
+/* Unlocked, I don't care if this is a bit off */
+int nsyscalls = 0;
long um_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
@@ -33,7 +38,7 @@ long sys_fork(void)
struct task_struct *p;
current->thread.forking = 1;
- p = do_fork(SIGCHLD, 0, NULL, 0, NULL);
+ p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
current->thread.forking = 0;
return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
}
@@ -43,7 +48,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp)
struct task_struct *p;
current->thread.forking = 1;
- p = do_fork(clone_flags, newsp, NULL, 0, NULL);
+ p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL);
current->thread.forking = 0;
return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
}
@@ -53,7 +58,7 @@ long sys_vfork(void)
struct task_struct *p;
current->thread.forking = 1;
- p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL);
+ p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL);
current->thread.forking = 0;
return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
}
@@ -182,7 +187,11 @@ int sys_ipc (uint call, int first, int second,
switch (call) {
case SEMOP:
- return sys_semop (first, (struct sembuf *)ptr, second);
+ return sys_semtimedop(first, (struct sembuf *) ptr, second,
+ NULL);
+ case SEMTIMEDOP:
+ return sys_semtimedop(first, (struct sembuf *) ptr, second,
+ (const struct timespec *) fifth);
case SEMGET:
return sys_semget (first, second, third);
case SEMCTL: {
@@ -298,122 +307,9 @@ int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
}
-static inline int check_area(void *ptr, int size)
-{
- return(verify_area(VERIFY_WRITE, ptr, size));
-}
-
-static int check_readlink(struct pt_regs *regs)
-{
- return(check_area((void *) regs->regs.args[1], regs->regs.args[2]));
-}
-
-static int check_utime(struct pt_regs *regs)
-{
- return(check_area((void *) regs->regs.args[1],
- sizeof(struct utimbuf)));
-}
-
-static int check_oldstat(struct pt_regs *regs)
-{
- return(check_area((void *) regs->regs.args[1],
- sizeof(struct __old_kernel_stat)));
-}
-
-static int check_stat(struct pt_regs *regs)
-{
- return(check_area((void *) regs->regs.args[1], sizeof(struct stat)));
-}
-
-static int check_stat64(struct pt_regs *regs)
-{
- return(check_area((void *) regs->regs.args[1], sizeof(struct stat64)));
-}
-
-struct bogus {
- int kernel_ds;
- int (*check_params)(struct pt_regs *);
-};
-
-struct bogus this_is_bogus[256] = {
- [ __NR_mknod ] = { 1, NULL },
- [ __NR_mkdir ] = { 1, NULL },
- [ __NR_rmdir ] = { 1, NULL },
- [ __NR_unlink ] = { 1, NULL },
- [ __NR_symlink ] = { 1, NULL },
- [ __NR_link ] = { 1, NULL },
- [ __NR_rename ] = { 1, NULL },
- [ __NR_umount ] = { 1, NULL },
- [ __NR_mount ] = { 1, NULL },
- [ __NR_pivot_root ] = { 1, NULL },
- [ __NR_chdir ] = { 1, NULL },
- [ __NR_chroot ] = { 1, NULL },
- [ __NR_open ] = { 1, NULL },
- [ __NR_quotactl ] = { 1, NULL },
- [ __NR_sysfs ] = { 1, NULL },
- [ __NR_readlink ] = { 1, check_readlink },
- [ __NR_acct ] = { 1, NULL },
- [ __NR_execve ] = { 1, NULL },
- [ __NR_uselib ] = { 1, NULL },
- [ __NR_statfs ] = { 1, NULL },
- [ __NR_truncate ] = { 1, NULL },
- [ __NR_access ] = { 1, NULL },
- [ __NR_chmod ] = { 1, NULL },
- [ __NR_chown ] = { 1, NULL },
- [ __NR_lchown ] = { 1, NULL },
- [ __NR_utime ] = { 1, check_utime },
- [ __NR_oldlstat ] = { 1, check_oldstat },
- [ __NR_oldstat ] = { 1, check_oldstat },
- [ __NR_stat ] = { 1, check_stat },
- [ __NR_lstat ] = { 1, check_stat },
- [ __NR_stat64 ] = { 1, check_stat64 },
- [ __NR_lstat64 ] = { 1, check_stat64 },
- [ __NR_chown32 ] = { 1, NULL },
-};
-
-/* sys_utimes */
-
-static int check_bogosity(struct pt_regs *regs)
-{
- struct bogus *bogon = &this_is_bogus[regs->regs.syscall];
-
- if(!bogon->kernel_ds) return(0);
- if(bogon->check_params && (*bogon->check_params)(regs))
- return(-EFAULT);
- set_fs(KERNEL_DS);
- return(0);
-}
-
-/* Unlocked, I don't care if this is a bit off */
-int nsyscalls = 0;
-
-extern syscall_handler_t *sys_call_table[];
-
long execute_syscall(void *r)
{
- struct pt_regs *regs = r;
- long res;
- int syscall;
-
- current->thread.nsyscalls++;
- nsyscalls++;
- syscall = regs->regs.syscall;
-
- if((syscall >= NR_syscalls) || (syscall < 0))
- res = -ENOSYS;
- else if(honeypot && check_bogosity(regs))
- res = -EFAULT;
- else res = EXECUTE_SYSCALL(syscall, regs);
-
- set_fs(USER_DS);
-
- if(current->thread.singlestep_syscall){
- current->thread.singlestep_syscall = 0;
- current->ptrace &= ~PT_DTRACE;
- force_sig(SIGTRAP, current);
- }
-
- return(res);
+ return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
}
spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
index 5da5aefce6d8..3712286fe5cb 100644
--- a/arch/um/kernel/syscall_user.c
+++ b/arch/um/kernel/syscall_user.c
@@ -1,30 +1,12 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
-/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately
- * after setting up syscall stack
- * block SIGVTALRM in any code that's under wait_for_stop
- */
-
-#include <unistd.h>
+#include <stdlib.h>
#include <sys/time.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/ptrace.h>
-#include <asm/unistd.h>
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "ptrace_user.h"
-#include "task.h"
-#include "user_util.h"
#include "kern_util.h"
-
-/* XXX Bogus */
-#define ERESTARTSYS 512
-#define ERESTARTNOINTR 513
-#define ERESTARTNOHAND 514
+#include "syscall_user.h"
struct {
int syscall;
@@ -34,67 +16,24 @@ struct {
struct timeval end;
} syscall_record[1024];
-void syscall_handler(int sig, struct uml_pt_regs *regs)
+int record_syscall_start(int syscall)
{
- void *sc;
- long result;
- int index, max, syscall;
+ int max, index;
max = sizeof(syscall_record)/sizeof(syscall_record[0]);
index = next_syscall_index(max);
- syscall = regs->syscall;
- sc = regs->sc;
- sc_to_regs(regs, sc, syscall);
- SC_START_SYSCALL(sc);
-
syscall_record[index].syscall = syscall;
syscall_record[index].pid = current_pid();
syscall_record[index].result = 0xdeadbeef;
gettimeofday(&syscall_record[index].start, NULL);
- syscall_trace();
- result = execute_syscall(regs);
-
- /* regs->sc may have changed while the system call ran (there may
- * have been an interrupt or segfault), so it needs to be refreshed.
- */
- regs->sc = sc;
-
- SC_SET_SYSCALL_RETURN(sc, result);
- if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
- (result == -ERESTARTNOINTR))
- do_signal(result);
-
- syscall_trace();
- syscall_record[index].result = result;
- gettimeofday(&syscall_record[index].end, NULL);
+ return(index);
}
-int do_syscall(void *task, int pid)
+void record_syscall_end(int index, int result)
{
- unsigned long proc_regs[FRAME_SIZE];
- struct uml_pt_regs *regs;
- int syscall;
-
- if(ptrace_getregs(pid, proc_regs) < 0)
- tracer_panic("Couldn't read registers");
- syscall = PT_SYSCALL_NR(proc_regs);
-
- regs = TASK_REGS(task);
- UPT_SYSCALL_NR(regs) = syscall;
-
- if(syscall < 1) return(0);
-
- if((syscall != __NR_sigreturn) &&
- ((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
- ((unsigned long *) PT_IP(proc_regs) <= &_etext))
- tracer_panic("I'm tracing myself and I can't get out");
-
- if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
- __NR_getpid) < 0)
- tracer_panic("do_syscall : Nullifying syscall failed, "
- "errno = %d", errno);
- return(1);
+ syscall_record[index].result = result;
+ gettimeofday(&syscall_record[index].end, NULL);
}
/*
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index 5a05d66a125f..2bf29ad7ad27 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -19,8 +19,8 @@
#ifdef CONFIG_MODULES
-extern struct module *module_list;
-extern struct module kernel_module;
+/* FIXME: Accessed without a lock --RR */
+extern struct list_head modules;
static inline int kernel_text_address(unsigned long addr)
{
@@ -31,11 +31,11 @@ static inline int kernel_text_address(unsigned long addr)
addr <= (unsigned long) &_etext)
return 1;
- for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+ list_for_each_entry(mod, &modules, list) {
/* mod_bound tests for addr being inside the vmalloc'ed
* module area. Of course it'd be better to test only
* for the .text subset... */
- if (mod_bound(addr, 0, mod)) {
+ if (mod_bound((void *) addr, 0, mod)) {
retval = 1;
break;
}
diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
index 0869e1a85ec9..64cd546a3a2d 100644
--- a/arch/um/kernel/tempfile.c
+++ b/arch/um/kernel/tempfile.c
@@ -11,7 +11,8 @@
#include <sys/param.h>
#include "init.h"
-char *tempdir = NULL;
+/* Modified from create_mem_file and start_debugger */
+static char *tempdir = NULL;
static void __init find_tempdir(void)
{
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 2ab57626b43f..282756af3779 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -23,22 +23,21 @@ void timer(void)
gettimeofday(&xtime, NULL);
}
-static void set_interval(int timer_type)
+void set_interval(int timer_type)
{
- struct itimerval interval;
+ int usec = 1000000/hz();
+ struct itimerval interval = ((struct itimerval) { { 0, usec },
+ { 0, usec } });
- interval.it_interval.tv_sec = 0;
- interval.it_interval.tv_usec = 1000000/hz();
- interval.it_value.tv_sec = 0;
- interval.it_value.tv_usec = 1000000/hz();
if(setitimer(timer_type, &interval, NULL) == -1)
panic("setitimer failed - errno = %d\n", errno);
}
void enable_timer(void)
{
- struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
- { 0, 1000000/hz() }});
+ int usec = 1000000/hz();
+ struct itimerval enable = ((struct itimerval) { { 0, usec },
+ { 0, usec }});
if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
printk("enable_timer - setitimer failed, errno = %d\n",
errno);
@@ -76,13 +75,6 @@ void idle_timer(void)
set_interval(ITIMER_REAL);
}
-void user_time_init(void)
-{
- if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
- panic("Couldn't set SIGVTALRM handler");
- set_interval(ITIMER_VIRTUAL);
-}
-
void time_init(void)
{
if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 93199e99c6f8..713d7af4a696 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -17,6 +17,7 @@
#include "kern_util.h"
#include "user_util.h"
#include "time_user.h"
+#include "mode.h"
u64 jiffies_64;
@@ -142,7 +143,7 @@ int __init timer_init(void)
{
int err;
- user_time_init();
+ CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer",
NULL)) != 0)
printk(KERN_ERR "timer_init : request_irq failed - "
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index f5e8458ff866..ea2ed5486881 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -1,232 +1,51 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
-#include "linux/sched.h"
-#include "linux/slab.h"
-#include "linux/bootmem.h"
+#include "linux/mm.h"
+#include "asm/page.h"
#include "asm/pgalloc.h"
-#include "asm-generic/tlb.h"
-#include "asm/pgtable.h"
-#include "asm/a.out.h"
-#include "asm/processor.h"
-#include "asm/mmu_context.h"
-#include "asm/uaccess.h"
-#include "asm/atomic.h"
-#include "mem_user.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "tlb.h"
-#include "os.h"
+#include "asm/tlbflush.h"
+#include "choose-mode.h"
+#include "mode_kern.h"
-static void fix_range(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force)
-{
- pgd_t *npgd;
- pmd_t *npmd;
- pte_t *npte;
- unsigned long addr;
- int r, w, x, err;
-
- if((current->thread.extern_pid != -1) &&
- (current->thread.extern_pid != os_getpid()))
- panic("fix_range fixing wrong address space, current = 0x%p",
- current);
- if(mm == NULL) return;
- for(addr=start_addr;addr<end_addr;){
- if(addr == TASK_SIZE){
- /* Skip over kernel text, kernel data, and physical
- * memory, which don't have ptes, plus kernel virtual
- * memory, which is flushed separately, and remap
- * the process stack. The only way to get here is
- * if (end_addr == STACK_TOP) > TASK_SIZE, which is
- * only true in the honeypot case.
- */
- addr = STACK_TOP - ABOVE_KMEM;
- continue;
- }
- npgd = pgd_offset(mm, addr);
- npmd = pmd_offset(npgd, addr);
- if(pmd_present(*npmd)){
- npte = pte_offset_kernel(npmd, addr);
- r = pte_read(*npte);
- w = pte_write(*npte);
- x = pte_exec(*npte);
- if(!pte_dirty(*npte)) w = 0;
- if(!pte_young(*npte)){
- r = 0;
- w = 0;
- }
- if(force || pte_newpage(*npte)){
- err = unmap((void *) addr, PAGE_SIZE);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- if(pte_present(*npte))
- map(addr, pte_val(*npte) & PAGE_MASK,
- PAGE_SIZE, r, w, x);
- }
- else if(pte_newprot(*npte)){
- protect(addr, PAGE_SIZE, r, w, x, 1);
- }
- *npte = pte_mkuptodate(*npte);
- addr += PAGE_SIZE;
- }
- else {
- if(force || pmd_newpage(*npmd)){
- err = unmap((void *) addr, PMD_SIZE);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- pmd_mkuptodate(*npmd);
- }
- addr += PMD_SIZE;
- }
- }
-}
-
-atomic_t vmchange_seq = ATOMIC_INIT(1);
-
-void flush_kernel_range(unsigned long start, unsigned long end, int update_seq)
-{
- struct mm_struct *mm;
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long addr;
- int updated = 0, err;
-
- mm = &init_mm;
- for(addr = start; addr < end;){
- pgd = pgd_offset(mm, addr);
- pmd = pmd_offset(pgd, addr);
- if(pmd_present(*pmd)){
- pte = pte_offset_kernel(pmd, addr);
- if(!pte_present(*pte) || pte_newpage(*pte)){
- updated = 1;
- err = unmap((void *) addr, PAGE_SIZE);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- if(pte_present(*pte))
- map(addr, pte_val(*pte) & PAGE_MASK,
- PAGE_SIZE, 1, 1, 1);
- }
- else if(pte_newprot(*pte)){
- updated = 1;
- protect(addr, PAGE_SIZE, 1, 1, 1, 1);
- }
- addr += PAGE_SIZE;
- }
- else {
- if(pmd_newpage(*pmd)){
- updated = 1;
- err = unmap((void *) addr, PMD_SIZE);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr += PMD_SIZE;
- }
- }
- if(updated && update_seq) atomic_inc(&vmchange_seq);
-}
-
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
- flush_kernel_range(start, end, 1);
-}
-
-static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
{
- int err;
-
- err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed);
- if(err == 0) return;
- else if((err == -EFAULT) || (err == -ENOMEM)){
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- protect_vm_page(addr, w, 1);
- }
- else panic("protect_vm_page : protect failed, errno = %d\n", err);
+ address &= PAGE_MASK;
+ flush_tlb_range(vma, address, address + PAGE_SIZE);
}
-void mprotect_kernel_vm(int w)
+void flush_tlb_all(void)
{
- struct mm_struct *mm;
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long addr;
-
- mm = &init_mm;
- for(addr = start_vm; addr < end_vm;){
- pgd = pgd_offset(mm, addr);
- pmd = pmd_offset(pgd, addr);
- if(pmd_present(*pmd)){
- pte = pte_offset_kernel(pmd, addr);
- if(pte_present(*pte)) protect_vm_page(addr, w, 0);
- addr += PAGE_SIZE;
- }
- else addr += PMD_SIZE;
- }
+ flush_tlb_mm(current->mm);
}
-
+
void flush_tlb_kernel_vm(void)
{
- flush_tlb_kernel_range(start_vm, end_vm);
+ CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas());
}
void __flush_tlb_one(unsigned long addr)
{
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
}
-
+
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
- if(vma->vm_mm != current->mm)
- return;
-
- /* Assumes that the range start ... end is entirely within
- * either process memory or kernel vm
- */
- if((start >= start_vm) && (start < end_vm))
- flush_kernel_range(start, end, 1);
- else fix_range(vma->vm_mm, start, end, 0);
+ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+ end);
}
void flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long seq;
-
- if(mm != current->mm)
- return;
-
- fix_range(mm, 0, STACK_TOP, 0);
-
- seq = atomic_read(&vmchange_seq);
- if(current->thread.vm_seq == seq) return;
- current->thread.vm_seq = seq;
- flush_kernel_range(start_vm, end_vm, 0);
-}
-
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
-void flush_tlb_all(void)
-{
- flush_tlb_mm(current->mm);
+ CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
}
void force_flush_all(void)
{
- fix_range(current->mm, 0, STACK_TOP, 1);
- flush_kernel_range(start_vm, end_vm, 0);
+ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
}
pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 33bfc04fc5d0..b93c2b4eb9c7 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -4,6 +4,7 @@
*/
#include "linux/kernel.h"
+#include "asm/errno.h"
#include "linux/sched.h"
#include "linux/mm.h"
#include "linux/spinlock.h"
@@ -19,41 +20,36 @@
#include "kern_util.h"
#include "kern.h"
#include "chan_kern.h"
-#include "debug.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
-extern int nsyscalls;
-
-unsigned long segv(unsigned long address, unsigned long ip, int is_write,
- int is_user, void *sc)
+int handle_page_fault(unsigned long address, unsigned long ip,
+ int is_write, int is_user, int *code_out)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
- struct siginfo si;
- void *catcher;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
unsigned long page;
+ int err = -EFAULT;
- if((address >= start_vm) && (address < end_vm)){
- flush_tlb_kernel_vm();
- return(0);
- }
- if(mm == NULL) panic("Segfault with no mm");
- catcher = current->thread.fault_catcher;
- si.si_code = SEGV_MAPERR;
+ *code_out = SEGV_MAPERR;
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
- if(!vma) goto bad;
- else if(vma->vm_start <= address) goto good_area;
- else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad;
- else if(expand_stack(vma, address)) goto bad;
+ if(!vma)
+ goto out;
+ else if(vma->vm_start <= address)
+ goto good_area;
+ else if(!(vma->vm_flags & VM_GROWSDOWN))
+ goto out;
+ else if(expand_stack(vma, address))
+ goto out;
good_area:
- si.si_code = SEGV_ACCERR;
- if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad;
+ *code_out = SEGV_ACCERR;
+ if(is_write && !(vma->vm_flags & VM_WRITE))
+ goto out;
page = address & PAGE_MASK;
if(page == (unsigned long) current->thread_info + PAGE_SIZE)
panic("Kernel stack overflow");
@@ -69,8 +65,10 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
current->maj_flt++;
break;
case VM_FAULT_SIGBUS:
- goto do_sigbus;
+ err = -EACCES;
+ goto out;
case VM_FAULT_OOM:
+ err = -ENOMEM;
goto out_of_memory;
default:
BUG();
@@ -80,44 +78,46 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
*pte = pte_mkyoung(*pte);
if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
flush_tlb_page(vma, page);
+ err = 0;
+ out:
up_read(&mm->mmap_sem);
- return(0);
-do_sigbus:
- up_read(&mm->mmap_sem);
+ return(err);
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRERR;
- si.si_addr = (void *)address;
- force_sig_info(SIGBUS, &si, current);
- if(!is_user) goto bad;
- return(0);
/*
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.
*/
out_of_memory:
- up_read(&mm->mmap_sem);
if (current->pid == 1) {
+ up_read(&mm->mmap_sem);
yield();
down_read(&mm->mmap_sem);
goto survive;
}
- printk("VM: killing process %s\n", current->comm);
- if(is_user)
- do_exit(SIGKILL);
+ err = -ENOMEM;
+ goto out;
+}
+
+unsigned long segv(unsigned long address, unsigned long ip, int is_write,
+ int is_user, void *sc)
+{
+ struct siginfo si;
+ void *catcher;
+ int err;
- /* Fall through to bad */
+ if(!is_user && (address >= start_vm) && (address < end_vm)){
+ flush_tlb_kernel_vm();
+ return(0);
+ }
+ if(current->mm == NULL) panic("Segfault with no mm");
+ err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
- bad:
- if(catcher != NULL){
+ catcher = current->thread.fault_catcher;
+ if(!err)
+ return(0);
+ else if(catcher != NULL){
current->thread.fault_addr = (void *) address;
- up_read(&mm->mmap_sem);
- do_longjmp(catcher);
+ do_longjmp(catcher, 1);
}
else if(current->thread.fault_addr != NULL){
panic("fault_addr set but no fault catcher");
@@ -125,15 +125,28 @@ out_of_memory:
else if(arch_fixup(ip, sc))
return(0);
- if(!is_user)
+ if(!is_user)
panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
address, ip);
- si.si_signo = SIGSEGV;
- si.si_addr = (void *) address;
- current->thread.cr2 = address;
- current->thread.err = is_write;
- force_sig_info(SIGSEGV, &si, current);
- up_read(&mm->mmap_sem);
+
+ if(err == -EACCES){
+ si.si_signo = SIGBUS;
+ si.si_errno = 0;
+ si.si_code = BUS_ADRERR;
+ si.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &si, current);
+ }
+ else if(err == -ENOMEM){
+ printk("VM: killing process %s\n", current->comm);
+ do_exit(SIGKILL);
+ }
+ else {
+ si.si_signo = SIGSEGV;
+ si.si_addr = (void *) address;
+ current->thread.cr2 = address;
+ current->thread.err = is_write;
+ force_sig_info(SIGSEGV, &si, current);
+ }
return(0);
}
@@ -161,7 +174,7 @@ void relay_signal(int sig, struct uml_pt_regs *regs)
void bus_handler(int sig, struct uml_pt_regs *regs)
{
if(current->thread.fault_catcher != NULL)
- do_longjmp(current->thread.fault_catcher);
+ do_longjmp(current->thread.fault_catcher, 1);
else relay_signal(sig, regs);
}
@@ -185,250 +198,6 @@ int next_trap_index(int limit)
return(ret);
}
-extern int debugger_pid;
-extern int debugger_fd;
-extern int debugger_parent;
-
-#ifdef CONFIG_PT_PROXY
-
-int debugger_signal(int status, pid_t pid)
-{
- return(debugger_proxy(status, pid));
-}
-
-void child_signal(pid_t pid, int status)
-{
- child_proxy(pid, status);
-}
-
-static void gdb_announce(char *dev_name, int dev)
-{
- printf("gdb assigned device '%s'\n", dev_name);
-}
-
-static struct chan_opts opts = {
- announce : gdb_announce,
- xterm_title : "UML kernel debugger",
- raw : 0,
- tramp_stack : 0,
- in_kernel : 0,
-};
-
-/* Accessed by the tracing thread, which automatically serializes access */
-static void *xterm_data;
-static int xterm_fd;
-
-extern void *xterm_init(char *, int, struct chan_opts *);
-extern int xterm_open(int, int, int, void *);
-extern void xterm_close(int, void *);
-
-int open_gdb_chan(void)
-{
- char stack[PAGE_SIZE];
-
- opts.tramp_stack = (unsigned long) stack;
- xterm_data = xterm_init("", 0, &opts);
- xterm_fd = xterm_open(1, 1, 1, xterm_data);
- return(xterm_fd);
-}
-
-static void exit_debugger_cb(void *unused)
-{
- if(debugger_pid != -1){
- if(gdb_pid != -1){
- fake_child_exit();
- gdb_pid = -1;
- }
- else kill_child_dead(debugger_pid);
- debugger_pid = -1;
- if(debugger_parent != -1)
- detach(debugger_parent, SIGINT);
- }
- if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
-}
-
-static void exit_debugger(void)
-{
- tracing_cb(exit_debugger_cb, NULL);
-}
-
-__uml_exitcall(exit_debugger);
-
-struct gdb_data {
- char *str;
- int err;
-};
-
-static void config_gdb_cb(void *arg)
-{
- struct gdb_data *data = arg;
- struct task_struct *task;
- int pid;
-
- data->err = -1;
- if(debugger_pid != -1) exit_debugger_cb(NULL);
- if(!strncmp(data->str, "pid,", strlen("pid,"))){
- data->str += strlen("pid,");
- pid = simple_strtoul(data->str, NULL, 0);
- task = cpu_tasks[0].task;
- debugger_pid = attach_debugger(task->thread.extern_pid,
- pid, 0);
- if(debugger_pid != -1){
- data->err = 0;
- gdb_pid = pid;
- }
- return;
- }
- data->err = 0;
- debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
- init_proxy(debugger_pid, 0, 0);
-}
-
-int gdb_config(char *str)
-{
- struct gdb_data data;
-
- if(*str++ != '=') return(-1);
- data.str = str;
- tracing_cb(config_gdb_cb, &data);
- return(data.err);
-}
-
-void remove_gdb_cb(void *unused)
-{
- exit_debugger_cb(NULL);
-}
-
-int gdb_remove(char *unused)
-{
- tracing_cb(remove_gdb_cb, NULL);
- return(0);
-}
-
-#ifdef CONFIG_MCONSOLE
-
-static struct mc_device gdb_mc = {
- name: "gdb",
- config: gdb_config,
- remove: gdb_remove,
-};
-
-int gdb_mc_init(void)
-{
- mconsole_register_dev(&gdb_mc);
- return(0);
-}
-
-__initcall(gdb_mc_init);
-
-#endif
-
-void signal_usr1(int sig)
-{
- if(debugger_pid != -1){
- printk(KERN_ERR "The debugger is already running\n");
- return;
- }
- debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
- init_proxy(debugger_pid, 0, 0);
-}
-
-int init_ptrace_proxy(int idle_pid, int startup, int stop)
-{
- int pid, status;
-
- pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
- status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
- if(pid < 0){
- cont(idle_pid);
- return(-1);
- }
- init_proxy(pid, 1, status);
- return(pid);
-}
-
-int attach_debugger(int idle_pid, int pid, int stop)
-{
- int status = 0, err;
-
- err = attach(pid);
- if(err < 0){
- printf("Failed to attach pid %d, errno = %d\n", pid, -err);
- return(-1);
- }
- if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
- init_proxy(pid, 1, status);
- return(pid);
-}
-
-#ifdef notdef /* Put this back in when it does something useful */
-static int __init uml_gdb_init_setup(char *line, int *add)
-{
- gdb_init = uml_strdup(line);
- return 0;
-}
-
-__uml_setup("gdb=", uml_gdb_init_setup,
-"gdb=<channel description>\n\n"
-);
-#endif
-
-static int __init uml_gdb_pid_setup(char *line, int *add)
-{
- gdb_pid = simple_strtoul(line, NULL, 0);
- *add = 0;
- return 0;
-}
-
-__uml_setup("gdb-pid=", uml_gdb_pid_setup,
-"gdb-pid=<pid>\n"
-" gdb-pid is used to attach an external debugger to UML. This may be\n"
-" an already-running gdb or a debugger-like process like strace.\n\n"
-);
-
-#else
-
-int debugger_signal(int status, pid_t pid){ return(0); }
-void child_signal(pid_t pid, int status){ }
-int init_ptrace_proxy(int idle_pid, int startup, int stop)
-{
- printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
- kill_child_dead(idle_pid);
- exit(1);
-}
-
-void signal_usr1(int sig)
-{
- printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
-}
-
-int attach_debugger(int idle_pid, int pid, int stop)
-{
- printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
- "is off\n");
- return(-1);
-}
-
-int config_gdb(char *str)
-{
- return(-1);
-}
-
-int remove_gdb(void)
-{
- return(-1);
-}
-
-int init_parent_proxy(int pid)
-{
- return(-1);
-}
-
-void debugger_parent_signal(int status, int pid)
-{
-}
-
-#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
index 8971a61c8310..02e7b0eede15 100644
--- a/arch/um/kernel/trap_user.c
+++ b/arch/um/kernel/trap_user.c
@@ -3,66 +3,33 @@
* Licensed under the GPL
*/
-#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
#include <errno.h>
-#include <sched.h>
#include <fcntl.h>
#include <setjmp.h>
-#include <string.h>
-#include <sys/ptrace.h>
+#include <signal.h>
#include <sys/time.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
#include <sys/ioctl.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
#include <asm/page.h>
#include <asm/unistd.h>
#include <asm/ptrace.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "signal_user.h"
-#include "mem_user.h"
-#include "user.h"
-#include "process.h"
+#include "init.h"
+#include "sysdep/ptrace.h"
#include "sigcontext.h"
#include "sysdep/sigcontext.h"
-#include "init.h"
-#include "chan_user.h"
#include "irq_user.h"
#include "frame_user.h"
-#include "syscall_user.h"
-#include "ptrace_user.h"
+#include "signal_user.h"
#include "time_user.h"
#include "task.h"
+#include "mode.h"
+#include "choose-mode.h"
+#include "kern_util.h"
+#include "user_util.h"
#include "os.h"
-static void signal_segv(int sig)
-{
- write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n"));
- for(;;) ;
-}
-
-int detach(int pid, int sig)
-{
- return(ptrace(PTRACE_DETACH, pid, 0, sig));
-}
-
-int attach(int pid)
-{
- int err;
-
- err = ptrace(PTRACE_ATTACH, pid, 0, 0);
- if(err < 0) return(-errno);
- else return(err);
-}
-
-int cont(int pid)
-{
- return(ptrace(PTRACE_CONT, pid, 0, 0));
-}
-
void kill_child_dead(int pid)
{
kill(pid, SIGKILL);
@@ -70,336 +37,6 @@ void kill_child_dead(int pid)
while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
}
-/* Changed early in boot, and then only read */
-int debug = 0;
-int debug_stop = 1;
-int debug_parent = 0;
-int honeypot = 0;
-
-static int signal_tramp(void *arg)
-{
- int (*proc)(void *);
-
- if(honeypot && munmap((void *) (host_task_size - 0x10000000),
- 0x10000000))
- panic("Unmapping stack failed");
- if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
- panic("ptrace PTRACE_TRACEME failed");
- os_stop_process(os_getpid());
- change_sig(SIGWINCH, 0);
- signal(SIGUSR1, SIG_IGN);
- change_sig(SIGCHLD, 0);
- signal(SIGSEGV, (__sighandler_t) sig_handler);
- set_cmdline("(idle thread)");
- set_init_pid(os_getpid());
- proc = arg;
- return((*proc)(NULL));
-}
-
-static void last_ditch_exit(int sig)
-{
- kmalloc_ok = 0;
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- uml_cleanup();
- exit(1);
-}
-
-static void sleeping_process_signal(int pid, int sig)
-{
- switch(sig){
- /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
- * right because the process must be in the kernel already.
- */
- case SIGCONT:
- case SIGTSTP:
- if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
- tracer_panic("sleeping_process_signal : Failed to "
- "continue pid %d, errno = %d\n", pid,
- sig);
- break;
-
- /* This happens when the debugger (e.g. strace) is doing system call
- * tracing on the kernel. During a context switch, the current task
- * will be set to the incoming process and the outgoing process will
- * hop into write and then read. Since it's not the current process
- * any more, the trace of those will land here. So, we need to just
- * PTRACE_SYSCALL it.
- */
- case SIGTRAP:
- if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
- tracer_panic("sleeping_process_signal : Failed to "
- "PTRACE_SYSCALL pid %d, errno = %d\n",
- pid, sig);
- break;
- case SIGSTOP:
- break;
- default:
- tracer_panic("sleeping process %d got unexpected "
- "signal : %d\n", pid, sig);
- break;
- }
-}
-
-/* Accessed only by the tracing thread */
-int debugger_pid = -1;
-int debugger_parent = -1;
-int debugger_fd = -1;
-int gdb_pid = -1;
-
-struct {
- int pid;
- int signal;
- unsigned long addr;
- struct timeval time;
-} signal_record[1024][32];
-
-int signal_index[32];
-int nsignals = 0;
-int debug_trace = 0;
-extern int io_nsignals, io_count, intr_count;
-
-extern void signal_usr1(int sig);
-
-int tracing_pid = -1;
-
-int signals(int (*init_proc)(void *), void *sp)
-{
- void *task = NULL;
- unsigned long eip = 0;
- int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
- int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
-
- capture_signal_stack();
- signal(SIGPIPE, SIG_IGN);
- setup_tracer_winch();
- tracing_pid = os_getpid();
- printf("tracing thread pid = %d\n", tracing_pid);
-
- pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
- n = waitpid(pid, &status, WUNTRACED);
- if(n < 0){
- printf("waitpid on idle thread failed, errno = %d\n", errno);
- exit(1);
- }
- if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
- printf("Failed to continue idle thread, errno = %d\n", errno);
- exit(1);
- }
-
- signal(SIGSEGV, signal_segv);
- signal(SIGUSR1, signal_usr1);
- set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
- set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
- set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
- if(debug_trace){
- printf("Tracing thread pausing to be attached\n");
- stop();
- }
- if(debug){
- if(gdb_pid != -1)
- debugger_pid = attach_debugger(pid, gdb_pid, 1);
- else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
- if(debug_parent){
- debugger_parent = os_process_parent(debugger_pid);
- init_parent_proxy(debugger_parent);
- err = attach(debugger_parent);
- if(err){
- printf("Failed to attach debugger parent %d, "
- "errno = %d\n", debugger_parent, err);
- debugger_parent = -1;
- }
- else {
- if(ptrace(PTRACE_SYSCALL, debugger_parent,
- 0, 0) < 0){
- printf("Failed to continue debugger "
- "parent, errno = %d\n", errno);
- debugger_parent = -1;
- }
- }
- }
- }
- set_cmdline("(tracing thread)");
- while(1){
- if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
- if(errno != ECHILD){
- printf("wait failed - errno = %d\n", errno);
- }
- continue;
- }
- if(pid == debugger_pid){
- int cont = 0;
-
- if(WIFEXITED(status) || WIFSIGNALED(status))
- debugger_pid = -1;
- /* XXX Figure out how to deal with gdb and SMP */
- else cont = debugger_signal(status, cpu_tasks[0].pid);
- if(cont == PTRACE_SYSCALL) strace = 1;
- continue;
- }
- else if(pid == debugger_parent){
- debugger_parent_signal(status, pid);
- continue;
- }
- nsignals++;
- if(WIFEXITED(status)) ;
-#ifdef notdef
- {
- printf("Child %d exited with status %d\n", pid,
- WEXITSTATUS(status));
- }
-#endif
- else if(WIFSIGNALED(status)){
- sig = WTERMSIG(status);
- if(sig != 9){
- printf("Child %d exited with signal %d\n", pid,
- sig);
- }
- }
- else if(WIFSTOPPED(status)){
- proc_id = pid_to_processor_id(pid);
- sig = WSTOPSIG(status);
- if(signal_index[proc_id] == 1024){
- signal_index[proc_id] = 0;
- last_index = 1023;
- }
- else last_index = signal_index[proc_id] - 1;
- if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
- (sig == SIGALRM)) &&
- (signal_record[proc_id][last_index].signal == sig)&&
- (signal_record[proc_id][last_index].pid == pid))
- signal_index[proc_id] = last_index;
- signal_record[proc_id][signal_index[proc_id]].pid = pid;
- gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
- eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
- signal_record[proc_id][signal_index[proc_id]].addr = eip;
- signal_record[proc_id][signal_index[proc_id]++].signal = sig;
-
- if(proc_id == -1){
- sleeping_process_signal(pid, sig);
- continue;
- }
-
- task = cpu_tasks[proc_id].task;
- tracing = is_tracing(task);
- old_tracing = tracing;
-
- switch(sig){
- case SIGUSR1:
- sig = 0;
- op = do_proc_op(task, proc_id);
- switch(op){
- case OP_TRACE_ON:
- arch_leave_kernel(task, pid);
- tracing = 1;
- break;
- case OP_REBOOT:
- case OP_HALT:
- unmap_physmem();
- kmalloc_ok = 0;
- ptrace(PTRACE_KILL, pid, 0, 0);
- return(op == OP_REBOOT);
- case OP_NONE:
- printf("Detaching pid %d\n", pid);
- detach(pid, SIGSTOP);
- continue;
- default:
- break;
- }
- /* OP_EXEC switches host processes on us,
- * we want to continue the new one.
- */
- pid = cpu_tasks[proc_id].pid;
- break;
- case SIGTRAP:
- if(!tracing && (debugger_pid != -1)){
- child_signal(pid, status);
- continue;
- }
- tracing = 0;
- if(do_syscall(task, pid)) sig = SIGUSR2;
- else clear_singlestep(task);
- break;
- case SIGPROF:
- if(tracing) sig = 0;
- break;
- case SIGCHLD:
- case SIGHUP:
- sig = 0;
- break;
- case SIGSEGV:
- case SIGIO:
- case SIGALRM:
- case SIGVTALRM:
- case SIGFPE:
- case SIGBUS:
- case SIGILL:
- case SIGWINCH:
- default:
- tracing = 0;
- break;
- }
- set_tracing(task, tracing);
-
- if(!tracing && old_tracing)
- arch_enter_kernel(task, pid);
-
- if(!tracing && (debugger_pid != -1) && (sig != 0) &&
- (sig != SIGALRM) && (sig != SIGVTALRM) &&
- (sig != SIGSEGV) && (sig != SIGTRAP) &&
- (sig != SIGUSR2) && (sig != SIGIO)){
- child_signal(pid, status);
- continue;
- }
-
- if(tracing){
- if(singlestepping(task))
- cont_type = PTRACE_SINGLESTEP;
- else cont_type = PTRACE_SYSCALL;
- }
- else cont_type = PTRACE_CONT;
-
- if((cont_type == PTRACE_CONT) &&
- (debugger_pid != -1) && strace)
- cont_type = PTRACE_SYSCALL;
-
- if(ptrace(cont_type, pid, 0, sig) != 0){
- tracer_panic("ptrace failed to continue "
- "process - errno = %d\n",
- errno);
- }
- }
- }
- return(0);
-}
-
-static int __init uml_debugtrace_setup(char *line, int *add)
-{
- debug_trace = 1;
- return 0;
-}
-__uml_setup("debugtrace", uml_debugtrace_setup,
-"debugtrace\n"
-" Causes the tracing thread to pause until it is attached by a\n"
-" debugger and continued. This is mostly for debugging crashes\n"
-" early during boot, and should be pretty much obsoleted by\n"
-" the debug switch.\n\n"
-);
-
-static int __init uml_honeypot_setup(char *line, int *add)
-{
- jail_setup("", add);
- honeypot = 1;
- return 0;
-}
-__uml_setup("honeypot", uml_honeypot_setup,
-"honeypot\n"
-" This makes UML put process stacks in the same location as they are\n"
-" on the host, allowing expoits such as stack smashes to work against\n"
-" UML. This implies 'jail'.\n\n"
-);
-
/* Unlocked - don't care if this is a bit off */
int nsegfaults = 0;
@@ -413,33 +50,32 @@ struct {
void segv_handler(int sig, struct uml_pt_regs *regs)
{
- struct sigcontext *context = regs->sc;
int index, max;
- if(regs->is_user && !SEGV_IS_FIXABLE(context)){
- bad_segv(SC_FAULT_ADDR(context), SC_IP(context),
- SC_FAULT_WRITE(context));
+ if(regs->is_user && !UPT_SEGV_IS_FIXABLE(regs)){
+ bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs),
+ UPT_FAULT_WRITE(regs));
return;
}
max = sizeof(segfault_record)/sizeof(segfault_record[0]);
index = next_trap_index(max);
nsegfaults++;
- segfault_record[index].address = SC_FAULT_ADDR(context);
+ segfault_record[index].address = UPT_FAULT_ADDR(regs);
segfault_record[index].pid = os_getpid();
- segfault_record[index].is_write = SC_FAULT_WRITE(context);
- segfault_record[index].sp = SC_SP(context);
+ segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
+ segfault_record[index].sp = UPT_SP(regs);
segfault_record[index].is_user = regs->is_user;
- segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context),
- regs->is_user, context);
+ segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
+ regs->is_user, regs);
}
-struct signal_info {
- void (*handler)(int, struct uml_pt_regs *);
- int is_irq;
-};
+void usr2_handler(int sig, struct uml_pt_regs *regs)
+{
+ CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
+}
-static struct signal_info sig_info[] = {
+struct signal_info sig_info[] = {
[ SIGTRAP ] { handler : relay_signal,
is_irq : 0 },
[ SIGFPE ] { handler : relay_signal,
@@ -454,104 +90,42 @@ static struct signal_info sig_info[] = {
is_irq : 1 },
[ SIGVTALRM ] { handler : timer_handler,
is_irq : 1 },
- [ SIGALRM ] { handler : timer_handler,
- is_irq : 1 },
- [ SIGUSR2 ] { handler : syscall_handler,
+ [ SIGALRM ] { handler : timer_handler,
+ is_irq : 1 },
+ [ SIGUSR2 ] { handler : usr2_handler,
is_irq : 0 },
};
-void sig_handler_common(int sig, struct sigcontext *sc)
-{
- struct uml_pt_regs save_regs, *r;
- struct signal_info *info;
- int save_errno = errno, is_user;
-
- unprotect_kernel_mem();
-
- r = (struct uml_pt_regs *) TASK_REGS(get_current());
- save_regs = *r;
- is_user = user_context(SC_SP(sc));
- r->is_user = is_user;
- r->sc = sc;
- if(sig != SIGUSR2) r->syscall = -1;
-
- change_sig(SIGUSR1, 1);
- info = &sig_info[sig];
- if(!info->is_irq) unblock_signals();
-
- (*info->handler)(sig, r);
-
- if(is_user){
- interrupt_end();
- block_signals();
- change_sig(SIGUSR1, 0);
- set_user_mode(NULL);
- }
- *r = save_regs;
- errno = save_errno;
- if(is_user) protect_kernel_mem();
-}
-
void sig_handler(int sig, struct sigcontext sc)
{
- sig_handler_common(sig, &sc);
+ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
+ sig, &sc);
}
extern int timer_irq_inited, missed_ticks[];
void alarm_handler(int sig, struct sigcontext sc)
{
- int user;
-
if(!timer_irq_inited) return;
missed_ticks[cpu()]++;
- user = user_context(SC_SP(&sc));
if(sig == SIGALRM)
switch_timers(0);
- sig_handler_common(sig, &sc);
+ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
+ sig, &sc);
if(sig == SIGALRM)
switch_timers(1);
}
-void do_longjmp(void *p)
+void do_longjmp(void *b, int val)
{
- jmp_buf *jbuf = (jmp_buf *) p;
+ jmp_buf *buf = b;
- longjmp(*jbuf, 1);
+ longjmp(*buf, val);
}
-static int __init uml_debug_setup(char *line, int *add)
-{
- char *next;
-
- debug = 1;
- *add = 0;
- if(*line != '=') return(0);
- line++;
-
- while(line != NULL){
- next = strchr(line, ',');
- if(next) *next++ = '\0';
-
- if(!strcmp(line, "go")) debug_stop = 0;
- else if(!strcmp(line, "parent")) debug_parent = 1;
- else printk("Unknown debug option : '%s'\n", line);
-
- line = next;
- }
- return(0);
-}
-
-__uml_setup("debug", uml_debug_setup,
-"debug\n"
-" Starts up the kernel under the control of gdb. See the \n"
-" kernel debugging tutorial and the debugging session pages\n"
-" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
-);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
new file mode 100644
index 000000000000..9b436c8ef1bb
--- /dev/null
+++ b/arch/um/kernel/tt/Makefile
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o ksyms.o mem.o process_kern.o \
+ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+ uaccess_user.o sys-$(SUBARCH)/
+
+obj-$(CONFIG_PT_PROXY) += ptproxy/
+
+export-objs = ksyms.o
+
+USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
new file mode 100644
index 000000000000..afd94713d742
--- /dev/null
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/mm.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/pgalloc.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+#include "time_user.h"
+#include "mem_user.h"
+#include "os.h"
+#include "tlb.h"
+
+static int exec_tramp(void *sig_stack)
+{
+ init_new_thread_stack(sig_stack, NULL);
+ init_new_thread_signals(1);
+ os_stop_process(os_getpid());
+ return(0);
+}
+
+void flush_thread_tt(void)
+{
+ unsigned long stack;
+ int new_pid;
+
+ stack = alloc_stack(0, 0);
+ if(stack == 0){
+ printk(KERN_ERR
+ "flush_thread : failed to allocate temporary stack\n");
+ do_exit(SIGKILL);
+ }
+
+ new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
+ stack, 0, exec_tramp);
+ if(new_pid < 0){
+ printk(KERN_ERR
+ "flush_thread : new thread failed, errno = %d\n",
+ -new_pid);
+ do_exit(SIGKILL);
+ }
+
+ if(current->thread_info->cpu == 0)
+ forward_interrupts(new_pid);
+ current->thread.request.op = OP_EXEC;
+ current->thread.request.u.exec.pid = new_pid;
+ unprotect_stack((unsigned long) current->thread_info);
+ os_usr1_process(os_getpid());
+
+ enable_timer();
+ free_page(stack);
+ protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+ task_protections((unsigned long) current->thread_info);
+ force_flush_all();
+ unblock_signals();
+}
+
+void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp)
+{
+ set_fs(USER_DS);
+ flush_tlb_mm(current->mm);
+ PT_REGS_IP(regs) = eip;
+ PT_REGS_SP(regs) = esp;
+ PT_FIX_EXEC_STACK(esp);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/exec_user.c b/arch/um/kernel/tt/exec_user.c
index 35d108266d41..35d108266d41 100644
--- a/arch/um/kernel/exec_user.c
+++ b/arch/um/kernel/tt/exec_user.c
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
new file mode 100644
index 000000000000..22753784178a
--- /dev/null
+++ b/arch/um/kernel/tt/gdb.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include "uml-config.h"
+#include "kern_constants.h"
+#include "chan_user.h"
+#include "init.h"
+#include "user.h"
+#include "debug.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "tt.h"
+#include "sysdep/thread.h"
+
+extern int debugger_pid;
+extern int debugger_fd;
+extern int debugger_parent;
+
+int detach(int pid, int sig)
+{
+ return(ptrace(PTRACE_DETACH, pid, 0, sig));
+}
+
+int attach(int pid)
+{
+ int err;
+
+ err = ptrace(PTRACE_ATTACH, pid, 0, 0);
+ if(err < 0) return(-errno);
+ else return(err);
+}
+
+int cont(int pid)
+{
+ return(ptrace(PTRACE_CONT, pid, 0, 0));
+}
+
+#ifdef CONFIG_PT_PROXY
+
+int debugger_signal(int status, pid_t pid)
+{
+ return(debugger_proxy(status, pid));
+}
+
+void child_signal(pid_t pid, int status)
+{
+ child_proxy(pid, status);
+}
+
+static void gdb_announce(char *dev_name, int dev)
+{
+ printf("gdb assigned device '%s'\n", dev_name);
+}
+
+static struct chan_opts opts = {
+ announce : gdb_announce,
+ xterm_title : "UML kernel debugger",
+ raw : 0,
+ tramp_stack : 0,
+ in_kernel : 0,
+};
+
+/* Accessed by the tracing thread, which automatically serializes access */
+static void *xterm_data;
+static int xterm_fd;
+
+extern void *xterm_init(char *, int, struct chan_opts *);
+extern int xterm_open(int, int, int, void *);
+extern void xterm_close(int, void *);
+
+int open_gdb_chan(void)
+{
+ char stack[UM_KERN_PAGE_SIZE];
+
+ opts.tramp_stack = (unsigned long) stack;
+ xterm_data = xterm_init("", 0, &opts);
+ xterm_fd = xterm_open(1, 1, 1, xterm_data);
+ return(xterm_fd);
+}
+
+static void exit_debugger_cb(void *unused)
+{
+ if(debugger_pid != -1){
+ if(gdb_pid != -1){
+ fake_child_exit();
+ gdb_pid = -1;
+ }
+ else kill_child_dead(debugger_pid);
+ debugger_pid = -1;
+ if(debugger_parent != -1)
+ detach(debugger_parent, SIGINT);
+ }
+ if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
+}
+
+static void exit_debugger(void)
+{
+ initial_thread_cb(exit_debugger_cb, NULL);
+}
+
+__uml_exitcall(exit_debugger);
+
+struct gdb_data {
+ char *str;
+ int err;
+};
+
+static void config_gdb_cb(void *arg)
+{
+ struct gdb_data *data = arg;
+ void *task;
+ int pid;
+
+ data->err = -1;
+ if(debugger_pid != -1) exit_debugger_cb(NULL);
+ if(!strncmp(data->str, "pid,", strlen("pid,"))){
+ data->str += strlen("pid,");
+ pid = strtoul(data->str, NULL, 0);
+ task = cpu_tasks[0].task;
+ debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
+ if(debugger_pid != -1){
+ data->err = 0;
+ gdb_pid = pid;
+ }
+ return;
+ }
+ data->err = 0;
+ debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+ init_proxy(debugger_pid, 0, 0);
+}
+
+int gdb_config(char *str)
+{
+ struct gdb_data data;
+
+ if(*str++ != '=') return(-1);
+ data.str = str;
+ initial_thread_cb(config_gdb_cb, &data);
+ return(data.err);
+}
+
+void remove_gdb_cb(void *unused)
+{
+ exit_debugger_cb(NULL);
+}
+
+int gdb_remove(char *unused)
+{
+ initial_thread_cb(remove_gdb_cb, NULL);
+ return(0);
+}
+
+void signal_usr1(int sig)
+{
+ if(debugger_pid != -1){
+ printk(UM_KERN_ERR "The debugger is already running\n");
+ return;
+ }
+ debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+ init_proxy(debugger_pid, 0, 0);
+}
+
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+ int pid, status;
+
+ pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
+ status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+ if(pid < 0){
+ cont(idle_pid);
+ return(-1);
+ }
+ init_proxy(pid, 1, status);
+ return(pid);
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+ int status = 0, err;
+
+ err = attach(pid);
+ if(err < 0){
+ printf("Failed to attach pid %d, errno = %d\n", pid, -err);
+ return(-1);
+ }
+ if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+ init_proxy(pid, 1, status);
+ return(pid);
+}
+
+#ifdef notdef /* Put this back in when it does something useful */
+static int __init uml_gdb_init_setup(char *line, int *add)
+{
+ gdb_init = uml_strdup(line);
+ return 0;
+}
+
+__uml_setup("gdb=", uml_gdb_init_setup,
+"gdb=<channel description>\n\n"
+);
+#endif
+
+static int __init uml_gdb_pid_setup(char *line, int *add)
+{
+ gdb_pid = strtoul(line, NULL, 0);
+ *add = 0;
+ return 0;
+}
+
+__uml_setup("gdb-pid=", uml_gdb_pid_setup,
+"gdb-pid=<pid>\n"
+" gdb-pid is used to attach an external debugger to UML. This may be\n"
+" an already-running gdb or a debugger-like process like strace.\n\n"
+);
+
+#else
+
+int debugger_signal(int status, pid_t pid){ return(0); }
+void child_signal(pid_t pid, int status){ }
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+ printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+ kill_child_dead(idle_pid);
+ exit(1);
+}
+
+void signal_usr1(int sig)
+{
+ printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+ printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
+ "is off\n");
+ return(-1);
+}
+
+int config_gdb(char *str)
+{
+ return(-1);
+}
+
+int remove_gdb(void)
+{
+ return(-1);
+}
+
+int init_parent_proxy(int pid)
+{
+ return(-1);
+}
+
+void debugger_parent_signal(int status, int pid)
+{
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
new file mode 100644
index 000000000000..2b4320c1480c
--- /dev/null
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/config.h"
+#include "mconsole_kern.h"
+
+#ifdef CONFIG_MCONSOLE
+
+extern int gdb_config(char *str);
+extern int gdb_remove(char *unused);
+
+static struct mc_device gdb_mc = {
+ name: "gdb",
+ config: gdb_config,
+ remove: gdb_remove,
+};
+
+int gdb_mc_init(void)
+{
+ mconsole_register_dev(&gdb_mc);
+ return(0);
+}
+
+__initcall(gdb_mc_init);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/include/debug.h b/arch/um/kernel/tt/include/debug.h
index 1d8b0a2638a8..8eff674107ca 100644
--- a/arch/um/include/debug.h
+++ b/arch/um/kernel/tt/include/debug.h
@@ -3,6 +3,7 @@
* Lars Brinkhoff.
* Licensed under the GPL
*/
+
#ifndef __DEBUG_H
#define __DEBUG_H
@@ -11,6 +12,8 @@ extern void child_proxy(pid_t pid, int status);
extern void init_proxy (pid_t pid, int waiting, int status);
extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
extern void fake_child_exit(void);
+extern int gdb_config(char *str);
+extern int gdb_remove(char *unused);
#endif
diff --git a/arch/um/kernel/setup.c b/arch/um/kernel/tt/include/mmu.h
index 3e4290a285f6..6b146bd84ca7 100644
--- a/arch/um/kernel/setup.c
+++ b/arch/um/kernel/tt/include/mmu.h
@@ -1,12 +1,15 @@
/*
- * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
-#include "asm/processor.h"
+#ifndef __TT_MMU_H
+#define __TT_MMU_H
-struct cpuinfo_um boot_cpu_data = { loops_per_jiffy : 0,
- ipi_pipe : { -1, -1 } };
+struct mmu_context_tt {
+};
+
+#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h
new file mode 100644
index 000000000000..183a61d40453
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_TT_H__
+#define __MODE_TT_H__
+
+#include "sysdep/ptrace.h"
+
+extern int tracing_pid;
+
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void user_time_init_tt(void);
+extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data);
+extern int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data);
+extern void sig_handler_common_tt(int sig, struct sigcontext *sc);
+extern void syscall_handler_tt(int sig, struct uml_pt_regs *regs);
+extern void reboot_tt(void);
+extern void halt_tt(void);
+extern int is_tracer_winch(int pid, int fd, void *data);
+extern void kill_off_processes_tt(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h
new file mode 100644
index 000000000000..3dbd434f1abe
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode_kern.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MODE_KERN_H__
+#define __TT_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+
+extern void *switch_to_tt(void *prev, void *next);
+extern void flush_thread_tt(void);
+extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp);
+extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+ unsigned long stack_top, struct task_struct *p,
+ struct pt_regs *regs);
+extern void release_thread_tt(struct task_struct *task);
+extern void exit_thread_tt(void);
+extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
+extern void init_idle_tt(void);
+extern void flush_tlb_kernel_vm_tt(void);
+extern void __flush_tlb_one_tt(unsigned long addr);
+extern void flush_tlb_range_tt(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+extern void flush_tlb_mm_tt(struct mm_struct *mm);
+extern void force_flush_all_tt(void);
+extern long execute_syscall_tt(void *r);
+extern void before_mem_tt(unsigned long brk_start);
+extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+ unsigned long *task_size_out);
+extern int start_uml_tt(void);
+extern struct page *arch_validate_tt(struct page *page, int mask, int order);
+extern int external_pid_tt(struct task_struct *task);
+extern int thread_pid_tt(struct task_struct *task);
+
+#define kmem_end_tt (host_task_size - ABOVE_KMEM)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/ptrace-tt.h b/arch/um/kernel/tt/include/ptrace-tt.h
new file mode 100644
index 000000000000..4e22b772c8f5
--- /dev/null
+++ b/arch/um/kernel/tt/include/ptrace-tt.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PTRACE_TT_H
+#define __PTRACE_TT_H
+
+#include "uml-config.h"
+
+#ifdef CONFIG_MODE_TT
+#include "sysdep/sc.h"
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
new file mode 100644
index 000000000000..3769d2aabc66
--- /dev/null
+++ b/arch/um/kernel/tt/include/tt.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_H__
+#define __TT_H__
+
+#include "sysdep/ptrace.h"
+
+extern int gdb_pid;
+extern int debug;
+extern int debug_stop;
+extern int debug_trace;
+
+extern int honeypot;
+
+extern int fork_tramp(void *sig_stack);
+extern int do_proc_op(void *t, int proc_id);
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void attach_process(int pid);
+extern void tracer_panic(char *format, ...);
+extern void set_init_pid(int pid);
+extern int set_user_mode(void *task);
+extern void set_tracing(void *t, int tracing);
+extern int is_tracing(void *task);
+extern int singlestepping_tt(void *t);
+extern void clear_singlestep(void *t);
+extern void syscall_handler(int sig, struct uml_pt_regs *regs);
+extern void exit_kernel(int pid, void *task);
+extern int do_syscall(void *task, int pid);
+extern int is_valid_pid(int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h
new file mode 100644
index 000000000000..902de9f3783c
--- /dev/null
+++ b/arch/um/kernel/tt/include/uaccess.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_UACCESS_H
+#define __TT_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+extern unsigned long end_vm;
+extern unsigned long uml_physmem;
+
+#define under_task_size(addr, size) \
+ (((unsigned long) (addr) < TASK_SIZE) && \
+ (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define is_stack(addr, size) \
+ (((unsigned long) (addr) < STACK_TOP) && \
+ ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
+ (((unsigned long) (addr) + (size)) <= STACK_TOP))
+
+#define access_ok_tt(type, addr, size) \
+ ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
+ (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
+ (under_task_size(addr, size) || is_stack(addr, size))))
+
+static inline int verify_area_tt(int type, const void * addr,
+ unsigned long size)
+{
+ return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern unsigned long get_fault_addr(void);
+
+extern int __do_copy_from_user(void *to, const void *from, int n,
+ void **fault_addr, void **fault_catcher);
+
+static inline int copy_from_user_tt(void *to, const void *from, int n)
+{
+ return(access_ok_tt(VERIFY_READ, from, n) ?
+ __do_copy_from_user(to, from, n,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher) : n);
+}
+
+extern int __do_copy_to_user(void *to, const void *from, int n,
+ void **fault_addr, void **fault_catcher);
+
+static inline int copy_to_user_tt(void *to, const void *from, int n)
+{
+ return(access_ok_tt(VERIFY_WRITE, to, n) ?
+ __do_copy_to_user(to, from, n,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher) : n);
+}
+
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+ void **fault_addr, void **fault_catcher);
+
+static inline int strncpy_from_user_tt(char *dst, const char *src, int count)
+{
+ int n;
+
+ if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT);
+ n = __do_strncpy_from_user(dst, src, count,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher);
+ if(n < 0) return(-EFAULT);
+ return(n);
+}
+
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+ void **fault_catcher);
+
+static inline int __clear_user_tt(void *mem, int len)
+{
+ return(__do_clear_user(mem, len,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+static inline int clear_user_tt(void *mem, int len)
+{
+ return(access_ok_tt(VERIFY_WRITE, mem, len) ?
+ __do_clear_user(mem, len,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher) : len);
+}
+
+extern int __do_strnlen_user(const char *str, unsigned long n,
+ void **fault_addr, void **fault_catcher);
+
+static inline int strnlen_user_tt(const void *str, int len)
+{
+ return(__do_strnlen_user(str, len,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
new file mode 100644
index 000000000000..92ec85d67c7c
--- /dev/null
+++ b/arch/um/kernel/tt/ksyms.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+#include "asm/uaccess.h"
+#include "mode.h"
+
+EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_copy_to_user);
+EXPORT_SYMBOL(__do_strncpy_from_user);
+EXPORT_SYMBOL(__do_strnlen_user);
+EXPORT_SYMBOL(__do_clear_user);
+
+EXPORT_SYMBOL(tracing_pid);
+EXPORT_SYMBOL(honeypot);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
new file mode 100644
index 000000000000..ff92e59bd86b
--- /dev/null
+++ b/arch/um/kernel/tt/mem.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "asm/uaccess.h"
+#include "mem_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "kern.h"
+#include "tt.h"
+
+void before_mem_tt(unsigned long brk_start)
+{
+ if(!jail || debug)
+ remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
+ remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
+ remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(brk_start), 1);
+}
+
+#ifdef CONFIG_HOST_2G_2G
+#define TOP 0x80000000
+#else
+#define TOP 0xc0000000
+#endif
+
+#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
+#define START (TOP - SIZE)
+
+unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+ unsigned long *task_size_out)
+{
+ /* Round up to the nearest 4M */
+ *host_size_out = ROUND_4M((unsigned long) &arg);
+ *task_size_out = START;
+ return(START);
+}
+
+struct page *arch_validate_tt(struct page *page, int mask, int order)
+{
+ unsigned long addr, zero = 0;
+ int i;
+
+ again:
+ if(page == NULL) return(page);
+ if(PageHighMem(page)) return(page);
+
+ addr = (unsigned long) page_address(page);
+ for(i = 0; i < (1 << order); i++){
+ current->thread.fault_addr = (void *) addr;
+ if(__do_copy_to_user((void *) addr, &zero,
+ sizeof(zero),
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher)){
+ if(!(mask & __GFP_WAIT)) return(NULL);
+ else break;
+ }
+ addr += PAGE_SIZE;
+ }
+ if(i == (1 << order)) return(page);
+ page = alloc_pages(mask, order);
+ goto again;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
new file mode 100644
index 000000000000..a9f6264d1fc9
--- /dev/null
+++ b/arch/um/kernel/tt/process_kern.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/signal.h"
+#include "linux/kernel.h"
+#include "asm/system.h"
+#include "asm/pgalloc.h"
+#include "asm/ptrace.h"
+#include "asm/tlbflush.h"
+#include "irq_user.h"
+#include "signal_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "kern.h"
+#include "sigcontext.h"
+#include "time_user.h"
+#include "mem_user.h"
+#include "tlb.h"
+#include "mode.h"
+#include "init.h"
+#include "tt.h"
+
+void *switch_to_tt(void *prev, void *next, void *last)
+{
+ struct task_struct *from, *to;
+ unsigned long flags;
+ int err, vtalrm, alrm, prof, cpu;
+ char c;
+ /* jailing and SMP are incompatible, so this doesn't need to be
+ * made per-cpu
+ */
+ static int reading;
+
+ from = prev;
+ to = next;
+
+ to->thread.prev_sched = from;
+
+ cpu = from->thread_info->cpu;
+ if(cpu == 0)
+ forward_interrupts(to->thread.mode.tt.extern_pid);
+#ifdef CONFIG_SMP
+ forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
+#endif
+ local_irq_save(flags);
+
+ vtalrm = change_sig(SIGVTALRM, 0);
+ alrm = change_sig(SIGALRM, 0);
+ prof = change_sig(SIGPROF, 0);
+
+ forward_pending_sigio(to->thread.mode.tt.extern_pid);
+
+ c = 0;
+ set_current(to);
+
+ reading = 0;
+ err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
+ if(err != sizeof(c))
+ panic("write of switch_pipe failed, errno = %d", -err);
+
+ reading = 1;
+ if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
+ os_kill_process(os_getpid(), 0);
+
+ err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
+ if(err != sizeof(c))
+ panic("read of switch_pipe failed, errno = %d", -err);
+
+ /* This works around a nasty race with 'jail'. If we are switching
+ * between two threads of a threaded app and the incoming process
+ * runs before the outgoing process reaches the read, and it makes
+ * it all the way out to userspace, then it will have write-protected
+ * the outgoing process stack. Then, when the outgoing process
+ * returns from the write, it will segfault because it can no longer
+ * write its own stack. So, in order to avoid that, the incoming
+ * thread sits in a loop yielding until 'reading' is set. This
+ * isn't entirely safe, since there may be a reschedule from a timer
+ * happening between setting 'reading' and sleeping in read. But,
+ * it should get a whole quantum in which to reach the read and sleep,
+ * which should be enough.
+ */
+
+ if(jail){
+ while(!reading) sched_yield();
+ }
+
+ change_sig(SIGVTALRM, vtalrm);
+ change_sig(SIGALRM, alrm);
+ change_sig(SIGPROF, prof);
+
+ arch_switch();
+
+ flush_tlb_all();
+ local_irq_restore(flags);
+
+ return(current->thread.prev_sched);
+}
+
+void release_thread_tt(struct task_struct *task)
+{
+ os_kill_process(task->thread.mode.tt.extern_pid, 0);
+}
+
+void exit_thread_tt(void)
+{
+ close(current->thread.mode.tt.switch_pipe[0]);
+ close(current->thread.mode.tt.switch_pipe[1]);
+}
+
+extern void schedule_tail(struct task_struct *prev);
+
+static void new_thread_handler(int sig)
+{
+ int (*fn)(void *);
+ void *arg;
+
+ fn = current->thread.request.u.thread.proc;
+ arg = current->thread.request.u.thread.arg;
+ current->thread.regs.regs.mode.tt = (void *) (&sig + 1);
+ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+ block_signals();
+ init_new_thread_signals(1);
+#ifdef CONFIG_SMP
+ schedule_tail(NULL);
+#endif
+ enable_timer();
+ free_page(current->thread.temp_stack);
+ set_cmdline("(kernel thread)");
+ force_flush_all();
+
+ current->thread.prev_sched = NULL;
+ change_sig(SIGUSR1, 1);
+ change_sig(SIGVTALRM, 1);
+ change_sig(SIGPROF, 1);
+ unblock_signals();
+ if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
+ do_exit(0);
+}
+
+static int new_thread_proc(void *stack)
+{
+ init_new_thread_stack(stack, new_thread_handler);
+ os_usr1_process(os_getpid());
+ return(0);
+}
+
+/* Signal masking - signals are blocked at the start of fork_tramp. They
+ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
+ * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
+ * so it is blocked before it's called. They are re-enabled on sigreturn
+ * despite the fact that they were blocked when the SIGUSR1 was issued because
+ * copy_thread copies the parent's signcontext, including the signal mask
+ * onto the signal frame.
+ */
+
+void finish_fork_handler(int sig)
+{
+ current->thread.regs.regs.mode.tt = (void *) (&sig + 1);
+ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+#ifdef CONFIG_SMP
+ schedule_tail(NULL);
+#endif
+ enable_timer();
+ change_sig(SIGVTALRM, 1);
+ force_flush_all();
+ if(current->mm != current->parent->mm)
+ protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
+ 1, 0, 1);
+ task_protections((unsigned long) current->thread_info);
+
+ current->thread.prev_sched = NULL;
+
+ free_page(current->thread.temp_stack);
+ change_sig(SIGUSR1, 0);
+ set_user_mode(current);
+}
+
+static int sigusr1 = SIGUSR1;
+
+int fork_tramp(void *stack)
+{
+ int sig = sigusr1;
+
+ init_new_thread_stack(stack, finish_fork_handler);
+
+ kill(os_getpid(), sig);
+ return(0);
+}
+
+int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+ unsigned long stack_top, struct task_struct * p,
+ struct pt_regs *regs)
+{
+ int (*tramp)(void *);
+ int new_pid, err;
+ unsigned long stack;
+
+ if(current->thread.forking)
+ tramp = fork_tramp;
+ else {
+ tramp = new_thread_proc;
+ p->thread.request.u.thread = current->thread.request.u.thread;
+ }
+
+ err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
+ if(err){
+ printk("copy_thread : pipe failed, errno = %d\n", -err);
+ return(err);
+ }
+
+ stack = alloc_stack(0, 0);
+ if(stack == 0){
+ printk(KERN_ERR "copy_thread : failed to allocate "
+ "temporary stack\n");
+ return(-ENOMEM);
+ }
+
+ clone_flags &= CLONE_VM;
+ p->thread.temp_stack = stack;
+ new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack,
+ clone_flags, tramp);
+ if(new_pid < 0){
+ printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
+ -new_pid);
+ return(new_pid);
+ }
+
+ if(current->thread.forking){
+ sc_to_sc(p->thread.regs.regs.mode.tt,
+ current->thread.regs.regs.mode.tt);
+ SC_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.tt, 0);
+ if(sp != 0) SC_SP(p->thread.regs.regs.mode.tt) = sp;
+ }
+ p->thread.mode.tt.extern_pid = new_pid;
+
+ current->thread.request.op = OP_FORK;
+ current->thread.request.u.fork.pid = new_pid;
+ os_usr1_process(os_getpid());
+ return(0);
+}
+
+void reboot_tt(void)
+{
+ current->thread.request.op = OP_REBOOT;
+ os_usr1_process(os_getpid());
+}
+
+void halt_tt(void)
+{
+ current->thread.request.op = OP_HALT;
+ os_usr1_process(os_getpid());
+}
+
+void kill_off_processes_tt(void)
+{
+ struct task_struct *p;
+ int me;
+
+ me = os_getpid();
+ for_each_process(p){
+ if(p->thread.mode.tt.extern_pid != me)
+ os_kill_process(p->thread.mode.tt.extern_pid, 0);
+ }
+ if(init_task.thread.mode.tt.extern_pid != me)
+ os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
+}
+
+void initial_thread_cb_tt(void (*proc)(void *), void *arg)
+{
+ if(os_getpid() == tracing_pid){
+ (*proc)(arg);
+ }
+ else {
+ current->thread.request.op = OP_CB;
+ current->thread.request.u.cb.proc = proc;
+ current->thread.request.u.cb.arg = arg;
+ os_usr1_process(os_getpid());
+ }
+}
+
+int do_proc_op(void *t, int proc_id)
+{
+ struct task_struct *task;
+ struct thread_struct *thread;
+ int op, pid;
+
+ task = t;
+ thread = &task->thread;
+ op = thread->request.op;
+ switch(op){
+ case OP_NONE:
+ case OP_TRACE_ON:
+ break;
+ case OP_EXEC:
+ pid = thread->request.u.exec.pid;
+ do_exec(thread->mode.tt.extern_pid, pid);
+ thread->mode.tt.extern_pid = pid;
+ cpu_tasks[task->thread_info->cpu].pid = pid;
+ break;
+ case OP_FORK:
+ attach_process(thread->request.u.fork.pid);
+ break;
+ case OP_CB:
+ (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
+ break;
+ case OP_REBOOT:
+ case OP_HALT:
+ break;
+ default:
+ tracer_panic("Bad op in do_proc_op");
+ break;
+ }
+ thread->request.op = OP_NONE;
+ return(op);
+}
+
+void init_idle_tt(void)
+{
+ default_idle();
+}
+
+/* Changed by jail_setup, which is a setup */
+int jail = 0;
+
+int __init jail_setup(char *line, int *add)
+{
+ int ok = 1;
+
+ if(jail) return(0);
+#ifdef CONFIG_SMP
+ printf("'jail' may not used used in a kernel with CONFIG_SMP "
+ "enabled\n");
+ ok = 0;
+#endif
+#ifdef CONFIG_HOSTFS
+ printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
+ "enabled\n");
+ ok = 0;
+#endif
+#ifdef CONFIG_MODULES
+ printf("'jail' may not used used in a kernel with CONFIG_MODULES "
+ "enabled\n");
+ ok = 0;
+#endif
+ if(!ok) exit(1);
+
+ /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
+ * Removing it from the bounding set eliminates the ability of anything
+ * to acquire it, and thus read or write kernel memory.
+ */
+ cap_lower(cap_bset, CAP_SYS_RAWIO);
+ jail = 1;
+ return(0);
+}
+
+__uml_setup("jail", jail_setup,
+"jail\n"
+" Enables the protection of kernel memory from processes.\n\n"
+);
+
+static void mprotect_kernel_mem(int w)
+{
+ unsigned long start, end;
+
+ if(!jail || (current == &init_task)) return;
+
+ start = (unsigned long) current->thread_info + PAGE_SIZE;
+ end = (unsigned long) current->thread_info + PAGE_SIZE * 4;
+ protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
+ protect_memory(end, high_physmem - end, 1, w, 1, 1);
+
+ start = (unsigned long) UML_ROUND_DOWN(&_stext);
+ end = (unsigned long) UML_ROUND_UP(&_etext);
+ protect_memory(start, end - start, 1, w, 1, 1);
+
+ start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end);
+ end = (unsigned long) UML_ROUND_UP(&_edata);
+ protect_memory(start, end - start, 1, w, 1, 1);
+
+ start = (unsigned long) UML_ROUND_DOWN(&__bss_start);
+ end = (unsigned long) UML_ROUND_UP(brk_start);
+ protect_memory(start, end - start, 1, w, 1, 1);
+
+ mprotect_kernel_vm(w);
+}
+
+void unprotect_kernel_mem(void)
+{
+ mprotect_kernel_mem(1);
+}
+
+void protect_kernel_mem(void)
+{
+ mprotect_kernel_mem(0);
+}
+
+extern void start_kernel(void);
+
+static int start_kernel_proc(void *unused)
+{
+ int pid;
+
+ block_signals();
+ pid = os_getpid();
+
+ cpu_tasks[0].pid = pid;
+ cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ cpu_online_map = 1;
+#endif
+ if(debug) os_stop_process(pid);
+ start_kernel();
+ return(0);
+}
+
+void set_tracing(void *task, int tracing)
+{
+ ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
+}
+
+int is_tracing(void *t)
+{
+ return (((struct task_struct *) t)->thread.mode.tt.tracing);
+}
+
+int set_user_mode(void *t)
+{
+ struct task_struct *task;
+
+ task = t ? t : current;
+ if(task->thread.mode.tt.tracing)
+ return(1);
+ task->thread.request.op = OP_TRACE_ON;
+ os_usr1_process(os_getpid());
+ return(0);
+}
+
+void set_init_pid(int pid)
+{
+ int err;
+
+ init_task.thread.mode.tt.extern_pid = pid;
+ err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
+ if(err) panic("Can't create switch pipe for init_task, errno = %d",
+ err);
+}
+
+int singlestepping_tt(void *t)
+{
+ struct task_struct *task = t;
+
+ if(task->thread.mode.tt.singlestep_syscall)
+ return(0);
+ return(task->ptrace & PT_DTRACE);
+}
+
+void clear_singlestep(void *t)
+{
+ struct task_struct *task = t;
+
+ task->ptrace &= ~PT_DTRACE;
+}
+
+int start_uml_tt(void)
+{
+ void *sp;
+
+ sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE -
+ sizeof(unsigned long);
+ return(tracer(start_kernel_proc, sp));
+}
+
+int external_pid_tt(struct task_struct *task)
+{
+ return(task->thread.mode.tt.extern_pid);
+}
+
+int thread_pid_tt(struct task_struct *task)
+{
+ return(task->thread.mode.tt.extern_pid);
+}
+
+int is_valid_pid(int pid)
+{
+ struct task_struct *task;
+
+ read_lock(&tasklist_lock);
+ for_each_process(task){
+ if(task->thread.mode.tt.extern_pid == pid){
+ read_unlock(&tasklist_lock);
+ return(1);
+ }
+ }
+ read_unlock(&tasklist_lock);
+ return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
new file mode 100644
index 000000000000..97d4f0bc18d7
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = proxy.o ptrace.o sysdep.o wait.o
+
+USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file))
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean:
diff --git a/arch/um/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
index d5cd8c8919ba..d5cd8c8919ba 100644
--- a/arch/um/ptproxy/proxy.c
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
diff --git a/arch/um/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
index 5eb0285b1968..5eb0285b1968 100644
--- a/arch/um/ptproxy/ptproxy.h
+++ b/arch/um/kernel/tt/ptproxy/ptproxy.h
diff --git a/arch/um/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
index 910d026677ca..721d0a306fde 100644
--- a/arch/um/ptproxy/ptrace.c
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -21,6 +21,7 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml
#include "user_util.h"
#include "kern_util.h"
#include "ptrace_user.h"
+#include "tt.h"
long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
long arg3, long arg4, pid_t child, int *ret)
diff --git a/arch/um/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
index 50a120d5e65c..50a120d5e65c 100644
--- a/arch/um/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
diff --git a/arch/um/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
index 735f488049aa..735f488049aa 100644
--- a/arch/um/ptproxy/sysdep.h
+++ b/arch/um/kernel/tt/ptproxy/sysdep.h
diff --git a/arch/um/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
index aad7e4b62ee5..aad7e4b62ee5 100644
--- a/arch/um/ptproxy/wait.c
+++ b/arch/um/kernel/tt/ptproxy/wait.c
diff --git a/arch/um/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
index 542e73ee2cee..542e73ee2cee 100644
--- a/arch/um/ptproxy/wait.h
+++ b/arch/um/kernel/tt/ptproxy/wait.h
diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile
new file mode 100644
index 000000000000..2ad8271c604d
--- /dev/null
+++ b/arch/um/kernel/tt/sys-i386/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = sigcontext.o
+
+USER_OBJS = sigcontext.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
diff --git a/arch/um/kernel/tt/sys-i386/sigcontext.c b/arch/um/kernel/tt/sys-i386/sigcontext.c
new file mode 100644
index 000000000000..1701c0dfb030
--- /dev/null
+++ b/arch/um/kernel/tt/sys-i386/sigcontext.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <asm/sigcontext.h>
+#include "kern_util.h"
+#include "sysdep/frame.h"
+
+int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data)
+{
+ struct arch_frame_data *arch = data;
+ struct sigcontext *to = to_ptr, *from = from_ptr;
+ struct _fpstate *to_fp, *from_fp;
+ unsigned long sigs;
+ int err;
+
+ to_fp = to->fpstate;
+ from_fp = from->fpstate;
+ sigs = to->oldmask;
+ err = copy_from_user_proc(to, from, sizeof(*to));
+ to->oldmask = sigs;
+ if(to_fp != NULL){
+ err |= copy_from_user_proc(&to->fpstate, &to_fp,
+ sizeof(to->fpstate));
+ err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
+ }
+ return(err);
+}
+
+int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data)
+{
+ struct arch_frame_data *arch = data;
+ struct sigcontext *to = to_ptr, *from = from_ptr;
+ struct _fpstate *to_fp, *from_fp;
+ int err;
+
+ to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
+ from_fp = from->fpstate;
+ err = copy_to_user_proc(to, from, sizeof(*to));
+ if(from_fp != NULL){
+ err |= copy_to_user_proc(&to->fpstate, &to_fp,
+ sizeof(to->fpstate));
+ err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
+ }
+ return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
new file mode 100644
index 000000000000..3fb449db2885
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/types.h"
+#include "linux/utime.h"
+#include "linux/sys.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/stat.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+static inline int check_area(void *ptr, int size)
+{
+ return(verify_area(VERIFY_WRITE, ptr, size));
+}
+
+static int check_readlink(struct pt_regs *regs)
+{
+ return(check_area((void *) regs->regs.args[1], regs->regs.args[2]));
+}
+
+static int check_utime(struct pt_regs *regs)
+{
+ return(check_area((void *) regs->regs.args[1],
+ sizeof(struct utimbuf)));
+}
+
+static int check_oldstat(struct pt_regs *regs)
+{
+ return(check_area((void *) regs->regs.args[1],
+ sizeof(struct __old_kernel_stat)));
+}
+
+static int check_stat(struct pt_regs *regs)
+{
+ return(check_area((void *) regs->regs.args[1], sizeof(struct stat)));
+}
+
+static int check_stat64(struct pt_regs *regs)
+{
+ return(check_area((void *) regs->regs.args[1], sizeof(struct stat64)));
+}
+
+struct bogus {
+ int kernel_ds;
+ int (*check_params)(struct pt_regs *);
+};
+
+struct bogus this_is_bogus[256] = {
+ [ __NR_mknod ] = { 1, NULL },
+ [ __NR_mkdir ] = { 1, NULL },
+ [ __NR_rmdir ] = { 1, NULL },
+ [ __NR_unlink ] = { 1, NULL },
+ [ __NR_symlink ] = { 1, NULL },
+ [ __NR_link ] = { 1, NULL },
+ [ __NR_rename ] = { 1, NULL },
+ [ __NR_umount ] = { 1, NULL },
+ [ __NR_mount ] = { 1, NULL },
+ [ __NR_pivot_root ] = { 1, NULL },
+ [ __NR_chdir ] = { 1, NULL },
+ [ __NR_chroot ] = { 1, NULL },
+ [ __NR_open ] = { 1, NULL },
+ [ __NR_quotactl ] = { 1, NULL },
+ [ __NR_sysfs ] = { 1, NULL },
+ [ __NR_readlink ] = { 1, check_readlink },
+ [ __NR_acct ] = { 1, NULL },
+ [ __NR_execve ] = { 1, NULL },
+ [ __NR_uselib ] = { 1, NULL },
+ [ __NR_statfs ] = { 1, NULL },
+ [ __NR_truncate ] = { 1, NULL },
+ [ __NR_access ] = { 1, NULL },
+ [ __NR_chmod ] = { 1, NULL },
+ [ __NR_chown ] = { 1, NULL },
+ [ __NR_lchown ] = { 1, NULL },
+ [ __NR_utime ] = { 1, check_utime },
+ [ __NR_oldlstat ] = { 1, check_oldstat },
+ [ __NR_oldstat ] = { 1, check_oldstat },
+ [ __NR_stat ] = { 1, check_stat },
+ [ __NR_lstat ] = { 1, check_stat },
+ [ __NR_stat64 ] = { 1, check_stat64 },
+ [ __NR_lstat64 ] = { 1, check_stat64 },
+ [ __NR_chown32 ] = { 1, NULL },
+};
+
+/* sys_utimes */
+
+static int check_bogosity(struct pt_regs *regs)
+{
+ struct bogus *bogon = &this_is_bogus[regs->regs.syscall];
+
+ if(!bogon->kernel_ds) return(0);
+ if(bogon->check_params && (*bogon->check_params)(regs))
+ return(-EFAULT);
+ set_fs(KERNEL_DS);
+ return(0);
+}
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall_tt(void *r)
+{
+ struct pt_regs *regs = r;
+ long res;
+ int syscall;
+
+ current->thread.nsyscalls++;
+ nsyscalls++;
+ syscall = regs->regs.syscall;
+
+ if((syscall >= NR_syscalls) || (syscall < 0))
+ res = -ENOSYS;
+ else if(honeypot && check_bogosity(regs))
+ res = -EFAULT;
+ else res = EXECUTE_SYSCALL(syscall, regs);
+
+ set_fs(USER_DS);
+
+ if(current->thread.mode.tt.singlestep_syscall){
+ current->thread.mode.tt.singlestep_syscall = 0;
+ current->ptrace &= ~PT_DTRACE;
+ force_sig(SIGTRAP, current);
+ }
+
+ return(res);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
new file mode 100644
index 000000000000..699e91f09c92
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "ptrace_user.h"
+#include "task.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "syscall_user.h"
+#include "tt.h"
+
+/* XXX Bogus */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514
+
+void syscall_handler_tt(int sig, struct uml_pt_regs *regs)
+{
+ void *sc;
+ long result;
+ int index, syscall;
+
+ syscall = regs->syscall;
+ sc = regs->mode.tt;
+ sc_to_regs(regs, sc, syscall);
+ SC_START_SYSCALL(sc);
+
+ index = record_syscall_start(syscall);
+ syscall_trace();
+ result = execute_syscall(regs);
+
+ /* regs->sc may have changed while the system call ran (there may
+ * have been an interrupt or segfault), so it needs to be refreshed.
+ */
+ regs->mode.tt = sc;
+
+ SC_SET_SYSCALL_RETURN(sc, result);
+ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
+ (result == -ERESTARTNOINTR))
+ do_signal(result);
+
+ syscall_trace();
+ record_syscall_end(index, result);
+}
+
+int do_syscall(void *task, int pid)
+{
+ unsigned long proc_regs[FRAME_SIZE];
+ struct uml_pt_regs *regs;
+ int syscall;
+
+ if(ptrace_getregs(pid, proc_regs) < 0)
+ tracer_panic("Couldn't read registers");
+ syscall = PT_SYSCALL_NR(proc_regs);
+
+ regs = TASK_REGS(task);
+ UPT_SYSCALL_NR(regs) = syscall;
+
+ if(syscall < 1) return(0);
+
+ if((syscall != __NR_sigreturn) &&
+ ((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
+ ((unsigned long *) PT_IP(proc_regs) <= &_etext))
+ tracer_panic("I'm tracing myself and I can't get out");
+
+ if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
+ __NR_getpid) < 0)
+ tracer_panic("do_syscall : Nullifying syscall failed, "
+ "errno = %d", errno);
+ return(1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
new file mode 100644
index 000000000000..8565b71b07cd
--- /dev/null
+++ b/arch/um/kernel/tt/time.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <sys/time.h>
+#include <time_user.h>
+#include "process.h"
+#include "user.h"
+
+void user_time_init_tt(void)
+{
+ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+ panic("Couldn't set SIGVTALRM handler");
+ set_interval(ITIMER_VIRTUAL);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
new file mode 100644
index 000000000000..e7e95a5c6ad2
--- /dev/null
+++ b/arch/um/kernel/tt/tlb.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "os.h"
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+ unsigned long end_addr, int force)
+{
+ pgd_t *npgd;
+ pmd_t *npmd;
+ pte_t *npte;
+ unsigned long addr;
+ int r, w, x, err;
+
+ if((current->thread.mode.tt.extern_pid != -1) &&
+ (current->thread.mode.tt.extern_pid != os_getpid()))
+ panic("fix_range fixing wrong address space, current = 0x%p",
+ current);
+ if(mm == NULL) return;
+ for(addr=start_addr;addr<end_addr;){
+ if(addr == TASK_SIZE){
+ /* Skip over kernel text, kernel data, and physical
+ * memory, which don't have ptes, plus kernel virtual
+ * memory, which is flushed separately, and remap
+ * the process stack. The only way to get here is
+ * if (end_addr == STACK_TOP) > TASK_SIZE, which is
+ * only true in the honeypot case.
+ */
+ addr = STACK_TOP - ABOVE_KMEM;
+ continue;
+ }
+ npgd = pgd_offset(mm, addr);
+ npmd = pmd_offset(npgd, addr);
+ if(pmd_present(*npmd)){
+ npte = pte_offset_kernel(npmd, addr);
+ r = pte_read(*npte);
+ w = pte_write(*npte);
+ x = pte_exec(*npte);
+ if(!pte_dirty(*npte)) w = 0;
+ if(!pte_young(*npte)){
+ r = 0;
+ w = 0;
+ }
+ if(force || pte_newpage(*npte)){
+ err = os_unmap_memory((void *) addr,
+ PAGE_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ if(pte_present(*npte))
+ map_memory(addr,
+ pte_val(*npte) & PAGE_MASK,
+ PAGE_SIZE, r, w, x);
+ }
+ else if(pte_newprot(*npte)){
+ protect_memory(addr, PAGE_SIZE, r, w, x, 1);
+ }
+ *npte = pte_mkuptodate(*npte);
+ addr += PAGE_SIZE;
+ }
+ else {
+ if(force || pmd_newpage(*npmd)){
+ err = os_unmap_memory((void *) addr, PMD_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ pmd_mkuptodate(*npmd);
+ }
+ addr += PMD_SIZE;
+ }
+ }
+}
+
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
+static void flush_kernel_vm_range(unsigned long start, unsigned long end,
+ int update_seq)
+{
+ struct mm_struct *mm;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr;
+ int updated = 0, err;
+
+ mm = &init_mm;
+ for(addr = start; addr < end;){
+ pgd = pgd_offset(mm, addr);
+ pmd = pmd_offset(pgd, addr);
+ if(pmd_present(*pmd)){
+ pte = pte_offset_kernel(pmd, addr);
+ if(!pte_present(*pte) || pte_newpage(*pte)){
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ PAGE_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ if(pte_present(*pte))
+ map_memory(addr,
+ pte_val(*pte) & PAGE_MASK,
+ PAGE_SIZE, 1, 1, 1);
+ }
+ else if(pte_newprot(*pte)){
+ updated = 1;
+ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
+ }
+ addr += PAGE_SIZE;
+ }
+ else {
+ if(pmd_newpage(*pmd)){
+ updated = 1;
+ err = os_unmap_memory((void *) addr, PMD_SIZE);
+ if(err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr += PMD_SIZE;
+ }
+ }
+ if(updated && update_seq) atomic_inc(&vmchange_seq);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ flush_kernel_vm_range(start, end, 1);
+}
+
+static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+{
+ int err;
+
+ err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
+ if(err == 0) return;
+ else if((err == -EFAULT) || (err == -ENOMEM)){
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+ protect_vm_page(addr, w, 1);
+ }
+ else panic("protect_vm_page : protect failed, errno = %d\n", err);
+}
+
+void mprotect_kernel_vm(int w)
+{
+ struct mm_struct *mm;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr;
+
+ mm = &init_mm;
+ for(addr = start_vm; addr < end_vm;){
+ pgd = pgd_offset(mm, addr);
+ pmd = pmd_offset(pgd, addr);
+ if(pmd_present(*pmd)){
+ pte = pte_offset_kernel(pmd, addr);
+ if(pte_present(*pte)) protect_vm_page(addr, w, 0);
+ addr += PAGE_SIZE;
+ }
+ else addr += PMD_SIZE;
+ }
+}
+
+void flush_tlb_kernel_vm_tt(void)
+{
+ flush_tlb_kernel_range(start_vm, end_vm);
+}
+
+void __flush_tlb_one_tt(unsigned long addr)
+{
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+}
+
+void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ if(vma->vm_mm != current->mm) return;
+
+ /* Assumes that the range start ... end is entirely within
+ * either process memory or kernel vm
+ */
+ if((start >= start_vm) && (start < end_vm))
+ flush_kernel_vm_range(start, end, 1);
+ else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm_tt(struct mm_struct *mm)
+{
+ unsigned long seq;
+
+ if(mm != current->mm) return;
+
+ fix_range(mm, 0, STACK_TOP, 0);
+
+ seq = atomic_read(&vmchange_seq);
+ if(current->thread.mode.tt.vm_seq == seq) return;
+ current->thread.mode.tt.vm_seq = seq;
+ flush_kernel_vm_range(start_vm, end_vm, 0);
+}
+
+void force_flush_all_tt(void)
+{
+ fix_range(current->mm, 0, STACK_TOP, 1);
+ flush_kernel_vm_range(start_vm, end_vm, 0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
new file mode 100644
index 000000000000..90e948c836bb
--- /dev/null
+++ b/arch/um/kernel/tt/tracer.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "os.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "process.h"
+#include "kern_util.h"
+#include "frame.h"
+#include "chan_user.h"
+#include "ptrace_user.h"
+#include "mode.h"
+#include "tt.h"
+
+static int tracer_winch[2];
+
+int is_tracer_winch(int pid, int fd, void *data)
+{
+ if(pid != tracing_pid)
+ return(0);
+
+ register_winch_irq(tracer_winch[0], fd, -1, data);
+ return(0);
+}
+
+static void tracer_winch_handler(int sig)
+{
+ char c = 1;
+
+ if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
+ printk("tracer_winch_handler - write failed, errno = %d\n",
+ errno);
+}
+
+/* Called only by the tracing thread during initialization */
+
+static void setup_tracer_winch(void)
+{
+ int err;
+
+ err = os_pipe(tracer_winch, 1, 1);
+ if(err){
+ printk("setup_tracer_winch : os_pipe failed, errno = %d\n",
+ -err);
+ return;
+ }
+ signal(SIGWINCH, tracer_winch_handler);
+}
+
+void attach_process(int pid)
+{
+ if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
+ (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
+ tracer_panic("OP_FORK failed to attach pid");
+ wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+ tracer_panic("OP_FORK failed to continue process");
+}
+
+void tracer_panic(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vprintf(format, ap);
+ printf("\n");
+ while(1) pause();
+}
+
+static void tracer_segv(int sig, struct sigcontext sc)
+{
+ printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
+ SC_FAULT_ADDR(&sc), SC_IP(&sc));
+ while(1)
+ pause();
+}
+
+/* Changed early in boot, and then only read */
+int debug = 0;
+int debug_stop = 1;
+int debug_parent = 0;
+int honeypot = 0;
+
+static int signal_tramp(void *arg)
+{
+ int (*proc)(void *);
+
+ if(honeypot && munmap((void *) (host_task_size - 0x10000000),
+ 0x10000000))
+ panic("Unmapping stack failed");
+ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+ panic("ptrace PTRACE_TRACEME failed");
+ os_stop_process(os_getpid());
+ change_sig(SIGWINCH, 0);
+ signal(SIGUSR1, SIG_IGN);
+ change_sig(SIGCHLD, 0);
+ signal(SIGSEGV, (__sighandler_t) sig_handler);
+ set_cmdline("(idle thread)");
+ set_init_pid(os_getpid());
+ proc = arg;
+ return((*proc)(NULL));
+}
+
+static void last_ditch_exit(int sig)
+{
+ kmalloc_ok = 0;
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ uml_cleanup();
+ exit(1);
+}
+
+static void sleeping_process_signal(int pid, int sig)
+{
+ switch(sig){
+ /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
+ * right because the process must be in the kernel already.
+ */
+ case SIGCONT:
+ case SIGTSTP:
+ if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
+ tracer_panic("sleeping_process_signal : Failed to "
+ "continue pid %d, errno = %d\n", pid,
+ sig);
+ break;
+
+ /* This happens when the debugger (e.g. strace) is doing system call
+ * tracing on the kernel. During a context switch, the current task
+ * will be set to the incoming process and the outgoing process will
+ * hop into write and then read. Since it's not the current process
+ * any more, the trace of those will land here. So, we need to just
+ * PTRACE_SYSCALL it.
+ */
+ case SIGTRAP:
+ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+ tracer_panic("sleeping_process_signal : Failed to "
+ "PTRACE_SYSCALL pid %d, errno = %d\n",
+ pid, sig);
+ break;
+ case SIGSTOP:
+ break;
+ default:
+ tracer_panic("sleeping process %d got unexpected "
+ "signal : %d\n", pid, sig);
+ break;
+ }
+}
+
+/* Accessed only by the tracing thread */
+int debugger_pid = -1;
+int debugger_parent = -1;
+int debugger_fd = -1;
+int gdb_pid = -1;
+
+struct {
+ int pid;
+ int signal;
+ unsigned long addr;
+ struct timeval time;
+} signal_record[1024][32];
+
+int signal_index[32];
+int nsignals = 0;
+int debug_trace = 0;
+extern int io_nsignals, io_count, intr_count;
+
+extern void signal_usr1(int sig);
+
+int tracing_pid = -1;
+
+int tracer(int (*init_proc)(void *), void *sp)
+{
+ void *task = NULL;
+ unsigned long eip = 0;
+ int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
+ int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
+
+ capture_signal_stack();
+ signal(SIGPIPE, SIG_IGN);
+ setup_tracer_winch();
+ tracing_pid = os_getpid();
+ printf("tracing thread pid = %d\n", tracing_pid);
+
+ pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
+ n = waitpid(pid, &status, WUNTRACED);
+ if(n < 0){
+ printf("waitpid on idle thread failed, errno = %d\n", errno);
+ exit(1);
+ }
+ if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
+ printf("Failed to continue idle thread, errno = %d\n", errno);
+ exit(1);
+ }
+
+ signal(SIGSEGV, (sighandler_t) tracer_segv);
+ signal(SIGUSR1, signal_usr1);
+ set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+ set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+ set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+ if(debug_trace){
+ printf("Tracing thread pausing to be attached\n");
+ stop();
+ }
+ if(debug){
+ if(gdb_pid != -1)
+ debugger_pid = attach_debugger(pid, gdb_pid, 1);
+ else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
+ if(debug_parent){
+ debugger_parent = os_process_parent(debugger_pid);
+ init_parent_proxy(debugger_parent);
+ err = attach(debugger_parent);
+ if(err){
+ printf("Failed to attach debugger parent %d, "
+ "errno = %d\n", debugger_parent, err);
+ debugger_parent = -1;
+ }
+ else {
+ if(ptrace(PTRACE_SYSCALL, debugger_parent,
+ 0, 0) < 0){
+ printf("Failed to continue debugger "
+ "parent, errno = %d\n", errno);
+ debugger_parent = -1;
+ }
+ }
+ }
+ }
+ set_cmdline("(tracing thread)");
+ while(1){
+ if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
+ if(errno != ECHILD){
+ printf("wait failed - errno = %d\n", errno);
+ }
+ continue;
+ }
+ if(pid == debugger_pid){
+ int cont = 0;
+
+ if(WIFEXITED(status) || WIFSIGNALED(status))
+ debugger_pid = -1;
+ /* XXX Figure out how to deal with gdb and SMP */
+ else cont = debugger_signal(status, cpu_tasks[0].pid);
+ if(cont == PTRACE_SYSCALL) strace = 1;
+ continue;
+ }
+ else if(pid == debugger_parent){
+ debugger_parent_signal(status, pid);
+ continue;
+ }
+ nsignals++;
+ if(WIFEXITED(status)) ;
+#ifdef notdef
+ {
+ printf("Child %d exited with status %d\n", pid,
+ WEXITSTATUS(status));
+ }
+#endif
+ else if(WIFSIGNALED(status)){
+ sig = WTERMSIG(status);
+ if(sig != 9){
+ printf("Child %d exited with signal %d\n", pid,
+ sig);
+ }
+ }
+ else if(WIFSTOPPED(status)){
+ proc_id = pid_to_processor_id(pid);
+ sig = WSTOPSIG(status);
+ if(signal_index[proc_id] == 1024){
+ signal_index[proc_id] = 0;
+ last_index = 1023;
+ }
+ else last_index = signal_index[proc_id] - 1;
+ if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
+ (sig == SIGALRM)) &&
+ (signal_record[proc_id][last_index].signal == sig)&&
+ (signal_record[proc_id][last_index].pid == pid))
+ signal_index[proc_id] = last_index;
+ signal_record[proc_id][signal_index[proc_id]].pid = pid;
+ gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
+ eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+ signal_record[proc_id][signal_index[proc_id]].addr = eip;
+ signal_record[proc_id][signal_index[proc_id]++].signal = sig;
+
+ if(proc_id == -1){
+ sleeping_process_signal(pid, sig);
+ continue;
+ }
+
+ task = cpu_tasks[proc_id].task;
+ tracing = is_tracing(task);
+ old_tracing = tracing;
+
+ switch(sig){
+ case SIGUSR1:
+ sig = 0;
+ op = do_proc_op(task, proc_id);
+ switch(op){
+ case OP_TRACE_ON:
+ arch_leave_kernel(task, pid);
+ tracing = 1;
+ break;
+ case OP_REBOOT:
+ case OP_HALT:
+ unmap_physmem();
+ kmalloc_ok = 0;
+ ptrace(PTRACE_KILL, pid, 0, 0);
+ return(op == OP_REBOOT);
+ case OP_NONE:
+ printf("Detaching pid %d\n", pid);
+ detach(pid, SIGSTOP);
+ continue;
+ default:
+ break;
+ }
+ /* OP_EXEC switches host processes on us,
+ * we want to continue the new one.
+ */
+ pid = cpu_tasks[proc_id].pid;
+ break;
+ case SIGTRAP:
+ if(!tracing && (debugger_pid != -1)){
+ child_signal(pid, status);
+ continue;
+ }
+ tracing = 0;
+ if(do_syscall(task, pid)) sig = SIGUSR2;
+ else clear_singlestep(task);
+ break;
+ case SIGPROF:
+ if(tracing) sig = 0;
+ break;
+ case SIGCHLD:
+ case SIGHUP:
+ sig = 0;
+ break;
+ case SIGSEGV:
+ case SIGIO:
+ case SIGALRM:
+ case SIGVTALRM:
+ case SIGFPE:
+ case SIGBUS:
+ case SIGILL:
+ case SIGWINCH:
+ default:
+ tracing = 0;
+ break;
+ }
+ set_tracing(task, tracing);
+
+ if(!tracing && old_tracing)
+ arch_enter_kernel(task, pid);
+
+ if(!tracing && (debugger_pid != -1) && (sig != 0) &&
+ (sig != SIGALRM) && (sig != SIGVTALRM) &&
+ (sig != SIGSEGV) && (sig != SIGTRAP) &&
+ (sig != SIGUSR2) && (sig != SIGIO) &&
+ (sig != SIGFPE)){
+ child_signal(pid, status);
+ continue;
+ }
+
+ if(tracing){
+ if(singlestepping_tt(task))
+ cont_type = PTRACE_SINGLESTEP;
+ else cont_type = PTRACE_SYSCALL;
+ }
+ else cont_type = PTRACE_CONT;
+
+ if((cont_type == PTRACE_CONT) &&
+ (debugger_pid != -1) && strace)
+ cont_type = PTRACE_SYSCALL;
+
+ if(ptrace(cont_type, pid, 0, sig) != 0){
+ tracer_panic("ptrace failed to continue "
+ "process - errno = %d\n",
+ errno);
+ }
+ }
+ }
+ return(0);
+}
+
+static int __init uml_debug_setup(char *line, int *add)
+{
+ char *next;
+
+ debug = 1;
+ *add = 0;
+ if(*line != '=') return(0);
+ line++;
+
+ while(line != NULL){
+ next = strchr(line, ',');
+ if(next) *next++ = '\0';
+
+ if(!strcmp(line, "go")) debug_stop = 0;
+ else if(!strcmp(line, "parent")) debug_parent = 1;
+ else printk("Unknown debug option : '%s'\n", line);
+
+ line = next;
+ }
+ return(0);
+}
+
+__uml_setup("debug", uml_debug_setup,
+"debug\n"
+" Starts up the kernel under the control of gdb. See the \n"
+" kernel debugging tutorial and the debugging session pages\n"
+" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
+);
+
+static int __init uml_debugtrace_setup(char *line, int *add)
+{
+ debug_trace = 1;
+ return 0;
+}
+__uml_setup("debugtrace", uml_debugtrace_setup,
+"debugtrace\n"
+" Causes the tracing thread to pause until it is attached by a\n"
+" debugger and continued. This is mostly for debugging crashes\n"
+" early during boot, and should be pretty much obsoleted by\n"
+" the debug switch.\n\n"
+);
+
+static int __init uml_honeypot_setup(char *line, int *add)
+{
+ jail_setup("", add);
+ honeypot = 1;
+ return 0;
+}
+__uml_setup("honeypot", uml_honeypot_setup,
+"honeypot\n"
+" This makes UML put process stacks in the same location as they are\n"
+" on the host, allowing expoits such as stack smashes to work against\n"
+" UML. This implies 'jail'.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
new file mode 100644
index 000000000000..37c8af88e39e
--- /dev/null
+++ b/arch/um/kernel/tt/trap_user.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "tt.h"
+
+void sig_handler_common_tt(int sig, struct sigcontext *sc)
+{
+ struct uml_pt_regs save_regs, *r;
+ struct signal_info *info;
+ int save_errno = errno, is_user;
+
+ unprotect_kernel_mem();
+
+ r = (struct uml_pt_regs *) TASK_REGS(get_current());
+ save_regs = *r;
+ is_user = user_context(SC_SP(sc));
+ r->is_user = is_user;
+ r->mode.tt = sc;
+ if(sig != SIGUSR2) r->syscall = -1;
+
+ change_sig(SIGUSR1, 1);
+ info = &sig_info[sig];
+ if(!info->is_irq) unblock_signals();
+
+ (*info->handler)(sig, r);
+
+ if(is_user){
+ interrupt_end();
+ block_signals();
+ change_sig(SIGUSR1, 0);
+ set_user_mode(NULL);
+ }
+ *r = save_regs;
+ errno = save_errno;
+ if(is_user) protect_kernel_mem();
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index 639ea1c4be37..639ea1c4be37 100644
--- a/arch/um/kernel/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
index 7d53a6ea2ab0..61c4cc3af749 100644
--- a/arch/um/kernel/tty_log.c
+++ b/arch/um/kernel/tty_log.c
@@ -103,7 +103,7 @@ static int __init set_tty_log_fd(char *name, int *add)
char *end;
tty_log_fd = strtoul(name, &end, 0);
- if(*end != '\0'){
+ if((*end != '\0') || (end == name)){
printk("set_tty_log_fd - strtoul failed on '%s'\n", name);
tty_log_fd = -1;
}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index b7d436981572..aacf0ca51a63 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -34,17 +34,21 @@
#include "initrd.h"
#include "init.h"
#include "os.h"
+#include "choose-mode.h"
+#include "mode_kern.h"
+#include "mode.h"
#define DEFAULT_COMMAND_LINE "root=6200"
struct cpuinfo_um boot_cpu_data = {
- .loops_per_jiffy = 0,
- .ipi_pipe = { -1, -1 }
+ .loops_per_jiffy = 0,
+ .ipi_pipe = { -1, -1 }
};
unsigned long thread_saved_pc(struct task_struct *task)
{
- return(os_process_pc(task->thread.extern_pid));
+ return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+ task)));
}
static int show_cpuinfo(struct seq_file *m, void *v)
@@ -93,47 +97,11 @@ pte_t * __bad_pagetable(void)
return(NULL);
}
-extern void start_kernel(void);
-
-extern int debug;
-extern int debug_stop;
-
-static int start_kernel_proc(void *unused)
-{
- int pid;
-
- block_signals();
- pid = os_getpid();
-
- cpu_tasks[0].pid = pid;
- cpu_tasks[0].task = current;
-#ifdef CONFIG_SMP
- cpu_online_map = 1;
-#endif
- if(debug) os_stop_process(pid);
- start_kernel();
- return(0);
-}
-
-#ifdef CONFIG_HOST_2G_2G
-#define TOP 0x80000000
-#else
-#define TOP 0xc0000000
-#endif
-
-#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
-#define START (TOP - SIZE)
-
-/* Set in main */
+/* Set in linux_main */
unsigned long host_task_size;
unsigned long task_size;
-void set_task_sizes(int arg)
-{
- /* Round up to the nearest 4M */
- host_task_size = ROUND_4M((unsigned long) &arg);
- task_size = START;
-}
+unsigned long uml_start;
/* Set in early boot */
unsigned long uml_physmem;
@@ -156,7 +124,8 @@ long physmem_size = 32 * 1024 * 1024;
void set_cmdline(char *cmd)
{
char *umid, *ptr;
- if(honeypot) return;
+
+ if(CHOOSE_MODE(honeypot, 0)) return;
umid = get_umid(1);
if(umid != NULL){
@@ -215,11 +184,48 @@ static int __init uml_ncpus_setup(char *line, int *add)
__uml_setup("ncpus=", uml_ncpus_setup,
"ncpus=<# of desired CPUs>\n"
-" This tells an SMP kernel how many virtual processors to start.\n"
-" Currently, this has no effect because SMP isn't enabled.\n\n"
+" This tells an SMP kernel how many virtual processors to start.\n\n"
);
#endif
+int force_tt = 0;
+
+#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
+#define DEFAULT_TT 0
+
+static int __init mode_tt_setup(char *line, int *add)
+{
+ force_tt = 1;
+ return(0);
+}
+
+__uml_setup("mode=tt", mode_tt_setup,
+"mode=tt\n"
+" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
+" forces UML to run in tt (tracing thread) mode. It is not the default\n"
+" because it's slower and less secure than skas mode.\n\n"
+);
+
+#else
+#ifdef CONFIG_MODE_SKAS
+
+#define DEFAULT_TT 0
+
+#else
+#ifdef CONFIG_MODE_TT
+
+#define DEFAULT_TT 1
+
+#else
+
+#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
+
+#endif
+#endif
+#endif
+
+int mode_tt = DEFAULT_TT;
+
static int __init Usage(char *line, int *add)
{
const char **p;
@@ -267,8 +273,6 @@ static void __init uml_postsetup(void)
return;
}
-extern int debug_trace;
-
/* Set during early boot */
unsigned long brk_start;
static struct vm_reserved kernel_vm_reserved;
@@ -280,7 +284,6 @@ int linux_main(int argc, char **argv)
unsigned long avail;
unsigned long virtmem_size, max_physmem;
unsigned int i, add, err;
- void *sp;
for (i = 1; i < argc; i++){
if((i == 1) && (argv[i][0] == ' ')) continue;
@@ -290,13 +293,14 @@ int linux_main(int argc, char **argv)
}
if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
- if(!jail || debug)
- remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
- remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
+ mode_tt = force_tt ? 1 : !can_do_skas();
+ uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
+ &host_task_size, &task_size);
+
brk_start = (unsigned long) sbrk(0);
- remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1);
+ CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
- uml_physmem = START;
+ uml_physmem = uml_start;
/* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M(brk_start) + (1 << 22);
@@ -331,8 +335,10 @@ int linux_main(int argc, char **argv)
virtmem_size);
err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
- if(err)
- tracer_panic("Failed to reserve VM area for kernel VM\n");
+ if(err){
+ printf("Failed to reserve VM area for kernel VM\n");
+ exit(1);
+ }
uml_postsetup();
@@ -340,9 +346,8 @@ int linux_main(int argc, char **argv)
2 * PAGE_SIZE;
task_protections((unsigned long) &init_thread_info);
- sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE -
- sizeof(unsigned long);
- return(signals(start_kernel_proc, sp));
+
+ return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
}
static int panic_exit(struct notifier_block *self, unsigned long unused1,
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 2ba2049510b3..e08acf5d5354 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -17,6 +17,8 @@
#include "umid.h"
#include "init.h"
#include "os.h"
+#include "user_util.h"
+#include "choose-mode.h"
#define UMID_LEN 64
#define UML_DIR "~/.uml/"
@@ -91,7 +93,7 @@ static int __init create_pid_file(void)
return 0;
}
- sprintf(pid, "%d\n", (tracing_pid == -1) ? os_getpid() : tracing_pid);
+ sprintf(pid, "%d\n", os_getpid());
if(write(fd, pid, strlen(pid)) != strlen(pid))
printk("Write of pid file failed - errno = %d\n", errno);
close(fd);
@@ -179,7 +181,7 @@ int not_dead_yet(char *dir)
dead = 1;
}
if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
- (p == tracing_pid))
+ (p == CHOOSE_MODE(tracing_pid, os_getpid())))
dead = 1;
}
if(!dead) return(1);
diff --git a/arch/um/main.c b/arch/um/main.c
index 204c7a189fdd..3addff95120c 100644
--- a/arch/um/main.c
+++ b/arch/um/main.c
@@ -17,6 +17,8 @@
#include "mem_user.h"
#include "user.h"
#include "init.h"
+#include "mode.h"
+#include "choose-mode.h"
/* Set in set_stklim, which is called from main and __wrap_malloc.
* __wrap_malloc only calls it if main hasn't started.
@@ -97,9 +99,6 @@ int main(int argc, char **argv, char **envp)
new_argv[i] = argv[i - 1];
new_argv[argc + 1] = NULL;
-#ifdef PROFILING
- disable_profile_timer();
-#endif
execvp(new_argv[0], new_argv);
perror("execing with extended args");
exit(1);
@@ -108,7 +107,6 @@ int main(int argc, char **argv, char **envp)
linux_prog = argv[0];
set_stklim();
- set_task_sizes(0);
if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
perror("Mallocing argv");
@@ -136,60 +134,14 @@ int main(int argc, char **argv, char **envp)
return(uml_exitcode);
}
-/* Changed in __wrap___monstartup and __wrap_malloc very early */
-static int allocating_monbuf = 0;
-
-#ifdef PROFILING
-extern void __real___monstartup (unsigned long, unsigned long);
-
-void __wrap___monstartup (unsigned long lowpc, unsigned long highpc)
-{
- allocating_monbuf = 1;
- __real___monstartup(lowpc, highpc);
- allocating_monbuf = 0;
- get_profile_timer();
-}
-#endif
+#define CAN_KMALLOC() \
+ (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1))
extern void *__real_malloc(int);
-extern unsigned long host_task_size;
-
-/* Set in __wrap_malloc early */
-static void *gmon_buf = NULL;
void *__wrap_malloc(int size)
{
- if(allocating_monbuf){
- unsigned long start, end;
- int fd;
-
- /* Turn this off now in case create_mem_file tries allocating
- * memory
- */
- allocating_monbuf = 0;
- fd = create_mem_file(size);
-
- /* Calculate this here because linux_main hasn't run yet
- * and host_task_size figures in STACK_TOP, which figures
- * in kmem_end.
- */
- set_task_sizes(0);
-
- /* Same with stacksizelim */
- set_stklim();
-
- end = get_kmem_end();
- start = (end - size) & PAGE_MASK;
- gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_FIXED, fd, 0);
- if(gmon_buf != (void *) start){
- perror("Creating gprof buffer");
- exit(1);
- }
- set_kmem_end(start);
- return(gmon_buf);
- }
- if(kmalloc_ok) return(um_kmalloc(size));
+ if(CAN_KMALLOC()) return(um_kmalloc(size));
else return(__real_malloc(size));
}
@@ -206,11 +158,7 @@ extern void __real_free(void *);
void __wrap_free(void *ptr)
{
- /* Could maybe unmap the gmon buffer, but we're just about to
- * exit anyway
- */
- if(ptr == gmon_buf) return;
- if(kmalloc_ok) kfree(ptr);
+ if(CAN_KMALLOC()) kfree(ptr);
else __real_free(ptr);
}
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index d36e16af7732..37eea4a327a2 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -3,12 +3,12 @@
# Licensed under the GPL
#
-obj-y = file.o process.o tty.o
+obj-y = file.o process.o tty.o drivers/
-USER_OBJS := $(foreach file,$(obj-y),arch/um/os-Linux/$(file))
+USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean :
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
index f3c044922133..52cae521eb65 100644
--- a/arch/um/os-Linux/drivers/Makefile
+++ b/arch/um/os-Linux/drivers/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 53e83d6607e1..318233b06e21 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -171,7 +171,8 @@ int os_pipe(int *fds, int stream, int close_on_exec)
int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
err = socketpair(AF_UNIX, type, 0, fds);
- if(err) return(-errno);
+ if(err)
+ return(-errno);
if(!close_on_exec)
return(0);
@@ -185,6 +186,7 @@ int os_pipe(int *fds, int stream, int close_on_exec)
int os_set_fd_async(int fd, int owner)
{
+ /* XXX This should do F_GETFL first */
if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
printk("os_set_fd_async : failed to set O_ASYNC and "
"O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index ca5df7d03495..b7a565a2d721 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -7,6 +7,8 @@
#include <stdio.h>
#include <errno.h>
#include <signal.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
#include "os.h"
#include "user.h"
@@ -75,9 +77,12 @@ void os_stop_process(int pid)
kill(pid, SIGSTOP);
}
-void os_kill_process(int pid)
+void os_kill_process(int pid, int reap_child)
{
kill(pid, SIGKILL);
+ if(reap_child)
+ waitpid(pid, NULL, 0);
+
}
void os_usr1_process(int pid)
@@ -90,6 +95,41 @@ int os_getpid(void)
return(getpid());
}
+int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len,
+ int r, int w, int x)
+{
+ void *loc;
+ int prot;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
+ fd, off);
+ if(loc < 0)
+ return(-errno);
+ return(0);
+}
+
+int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
+{
+ int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0));
+
+ if(mprotect(addr, len, prot) < 0)
+ return(-errno);
+ return(0);
+}
+
+int os_unmap_memory(void *addr, int len)
+{
+ int err;
+
+ err = munmap(addr, len);
+ if(err < 0) return(-errno);
+ return(0);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
index 64a5c21bda29..2866ddbc9203 100644
--- a/arch/um/os-Linux/tty.c
+++ b/arch/um/os-Linux/tty.c
@@ -35,7 +35,7 @@ int get_pty(void)
}
info.fd = fd;
- tracing_cb(grantpt_cb, &info);
+ initial_thread_cb(grantpt_cb, &info);
if(info.res < 0){
printk("get_pty : Couldn't grant pty - errno = %d\n",
diff --git a/arch/um/ptproxy/Makefile b/arch/um/ptproxy/Makefile
deleted file mode 100644
index fdb1ba781043..000000000000
--- a/arch/um/ptproxy/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-y = proxy.o ptrace.o sysdep.o wait.o
-
-USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file))
-
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
-
-clean:
- rm -f *.o core child ptproxy
-
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 19258ea6e695..bc0cbe6ba325 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,4 +1,4 @@
-obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o \
+obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \
ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
obj-$(CONFIG_HIGHMEM) += highmem.o
@@ -6,28 +6,26 @@ obj-$(CONFIG_HIGHMEM) += highmem.o
export-objs = ksyms.o
USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
-USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/sys-i386/$(file))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-SYMLINKS = semaphore.c checksum.S extable.c highmem.c
+SYMLINKS = semaphore.c extable.c highmem.c module.c
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+semaphore.c-dir = kernel
+extable.c-dir = mm
+highmem.c-dir = mm
+module.c-dir = kernel
-arch/um/sys-i386/checksum.S:
- -rm -f $@
- -ln -s $(TOPDIR)/arch/i386/lib/$(notdir $@) $@
+define make_link
+ -rm -f $1
+ ln -sf $(TOPDIR)/arch/i386/$($(notdir $1)-dir)/$(notdir $1) $1
+endef
-arch/um/sys-i386/semaphore.c:
- -rm -f $@
- -ln -s $(TOPDIR)/arch/i386/kernel/$(notdir $@) $@
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-arch/um/sys-i386/extable.c:
- -rm -f $@
- -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@
+$(foreach f,$(SYMLINKS),$(src)/$f):
+ $(call make_link,$@)
-arch/um/sys-i386/highmem.c:
- -rm -f $@
- -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@
clean:
$(MAKE) -C util clean
diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S
new file mode 100644
index 000000000000..a11171fb6223
--- /dev/null
+++ b/arch/um/sys-i386/checksum.S
@@ -0,0 +1,460 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/errno.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+.text
+.align 4
+.globl arch_csum_partial
+
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+arch_csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: unsigned char *buff
+ testl $2, %esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%esi), %bx
+ addl $2, %esi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, %edx
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+1: movl (%esi), %ebx
+ adcl %ebx, %eax
+ movl 4(%esi), %ebx
+ adcl %ebx, %eax
+ movl 8(%esi), %ebx
+ adcl %ebx, %eax
+ movl 12(%esi), %ebx
+ adcl %ebx, %eax
+ movl 16(%esi), %ebx
+ adcl %ebx, %eax
+ movl 20(%esi), %ebx
+ adcl %ebx, %eax
+ movl 24(%esi), %ebx
+ adcl %ebx, %eax
+ movl 28(%esi), %ebx
+ adcl %ebx, %eax
+ lea 32(%esi), %esi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+3: adcl (%esi), %eax
+ lea 4(%esi), %esi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+ movw (%esi),%cx
+ leal 2(%esi),%esi
+ je 6f
+ shll $16,%ecx
+5: movb (%esi),%cl
+6: addl %ecx,%eax
+ adcl $0, %eax
+7:
+ popl %ebx
+ popl %esi
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+arch_csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: const unsigned char *buf
+
+ testl $2, %esi
+ jnz 30f
+10:
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ andl $0x7c, %ebx
+ shrl $7, %ecx
+ addl %ebx,%esi
+ shrl $2, %ebx
+ negl %ebx
+ lea 45f(%ebx,%ebx,2), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%esi), %ax
+ lea 2(%esi), %esi
+ adcl $0, %eax
+ jmp 10b
+
+30: subl $2, %ecx
+ ja 20b
+ je 32f
+ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
+ addl %ebx, %eax
+ adcl $0, %eax
+ jmp 80f
+32:
+ addw (%esi), %ax # csumming 2 bytes, 2-aligned
+ adcl $0, %eax
+ jmp 80f
+
+40:
+ addl -128(%esi), %eax
+ adcl -124(%esi), %eax
+ adcl -120(%esi), %eax
+ adcl -116(%esi), %eax
+ adcl -112(%esi), %eax
+ adcl -108(%esi), %eax
+ adcl -104(%esi), %eax
+ adcl -100(%esi), %eax
+ adcl -96(%esi), %eax
+ adcl -92(%esi), %eax
+ adcl -88(%esi), %eax
+ adcl -84(%esi), %eax
+ adcl -80(%esi), %eax
+ adcl -76(%esi), %eax
+ adcl -72(%esi), %eax
+ adcl -68(%esi), %eax
+ adcl -64(%esi), %eax
+ adcl -60(%esi), %eax
+ adcl -56(%esi), %eax
+ adcl -52(%esi), %eax
+ adcl -48(%esi), %eax
+ adcl -44(%esi), %eax
+ adcl -40(%esi), %eax
+ adcl -36(%esi), %eax
+ adcl -32(%esi), %eax
+ adcl -28(%esi), %eax
+ adcl -24(%esi), %eax
+ adcl -20(%esi), %eax
+ adcl -16(%esi), %eax
+ adcl -12(%esi), %eax
+ adcl -8(%esi), %eax
+ adcl -4(%esi), %eax
+45:
+ lea 128(%esi), %esi
+ adcl $0, %eax
+ dec %ecx
+ jge 40b
+ movl %edx, %ecx
+50: andl $3, %ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%ebx # by the shll and shrl instructions
+ shll $3,%ecx
+ shrl %cl,%ebx
+ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
+ addl %ebx,%eax
+ adcl $0,%eax
+80:
+ popl %ebx
+ popl %esi
+ ret
+
+#endif
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ * DST definitions? It's damn hard to trigger all cases. I hope I got
+ * them all but there's no guarantee.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+.align 4
+.globl csum_partial_copy_generic_i386
+
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+
+#define ARGBASE 16
+#define FP 12
+
+csum_partial_copy_generic_i386:
+ subl $4,%esp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ movl ARGBASE+16(%esp),%eax # sum
+ movl ARGBASE+12(%esp),%ecx # len
+ movl ARGBASE+4(%esp),%esi # src
+ movl ARGBASE+8(%esp),%edi # dst
+
+ testl $2, %edi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+SRC(1: movw (%esi), %bx )
+ addl $2, %esi
+DST( movw %bx, (%edi) )
+ addl $2, %edi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, FP(%esp)
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+SRC(1: movl (%esi), %ebx )
+SRC( movl 4(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 4(%edi) )
+
+SRC( movl 8(%esi), %ebx )
+SRC( movl 12(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 8(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 12(%edi) )
+
+SRC( movl 16(%esi), %ebx )
+SRC( movl 20(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 16(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 20(%edi) )
+
+SRC( movl 24(%esi), %ebx )
+SRC( movl 28(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 24(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 28(%edi) )
+
+ lea 32(%esi), %esi
+ lea 32(%edi), %edi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl FP(%esp), %edx
+ movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+SRC(3: movl (%esi), %ebx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ lea 4(%esi), %esi
+ lea 4(%edi), %edi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+SRC( movw (%esi), %cx )
+ leal 2(%esi), %esi
+DST( movw %cx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%ecx
+SRC(5: movb (%esi), %cl )
+DST( movb %cl, (%edi) )
+6: addl %ecx, %eax
+ adcl $0, %eax
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+
+6001:
+ movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+
+ # zero the complete destination - computing the rest
+ # is too much work
+ movl ARGBASE+8(%esp), %edi # dst
+ movl ARGBASE+12(%esp), %ecx # len
+ xorl %eax,%eax
+ rep ; stosb
+
+ jmp 5000b
+
+6002:
+ movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT,(%ebx)
+ jmp 5000b
+
+.previous
+
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ecx # equivalent to addl $4,%esp
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+#define ROUND1(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ addl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ROUND(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ adcl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ARGBASE 12
+
+csum_partial_copy_generic_i386:
+ pushl %ebx
+ pushl %edi
+ pushl %esi
+ movl ARGBASE+4(%esp),%esi #src
+ movl ARGBASE+8(%esp),%edi #dst
+ movl ARGBASE+12(%esp),%ecx #len
+ movl ARGBASE+16(%esp),%eax #sum
+# movl %ecx, %edx
+ movl %ecx, %ebx
+ movl %esi, %edx
+ shrl $6, %ecx
+ andl $0x3c, %ebx
+ negl %ebx
+ subl %ebx, %esi
+ subl %ebx, %edi
+ lea -1(%esi),%edx
+ andl $-32,%edx
+ lea 3f(%ebx,%ebx), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+1: addl $64,%esi
+ addl $64,%edi
+ SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
+ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
+3: adcl $0,%eax
+ addl $64, %edx
+ dec %ecx
+ jge 1b
+4: movl ARGBASE+12(%esp),%edx #len
+ andl $3, %edx
+ jz 7f
+ cmpl $2, %edx
+ jb 5f
+SRC( movw (%esi), %dx )
+ leal 2(%esi), %esi
+DST( movw %dx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%edx
+5:
+SRC( movb (%esi), %dl )
+DST( movb %dl, (%edi) )
+6: addl %edx, %eax
+ adcl $0, %eax
+7:
+.section .fixup, "ax"
+6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+ # zero the complete destination (computing the rest is too much work)
+ movl ARGBASE+8(%esp),%edi # dst
+ movl ARGBASE+12(%esp),%ecx # len
+ xorl %eax,%eax
+ rep; stosb
+ jmp 7b
+6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT, (%ebx)
+ jmp 7b
+.previous
+
+ popl %esi
+ popl %edi
+ popl %ebx
+ ret
+
+#undef ROUND
+#undef ROUND1
+
+#endif
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
index bf57ac7e04e1..74f70a120458 100644
--- a/arch/um/sys-i386/ksyms.c
+++ b/arch/um/sys-i386/ksyms.c
@@ -13,4 +13,5 @@ EXPORT_SYMBOL(__down_failed_trylock);
EXPORT_SYMBOL(__up_wakeup);
/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(csum_partial_copy_from);
+EXPORT_SYMBOL(csum_partial_copy_to);
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 7af4ef3d5dfd..33e302160d7c 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -3,15 +3,82 @@
* Licensed under the GPL
*/
+#include "linux/config.h"
+#include "linux/slab.h"
#include "asm/uaccess.h"
+#include "asm/ptrace.h"
+#include "choose-mode.h"
+#include "kern.h"
+#ifdef CONFIG_MODE_TT
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
-int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
{
if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
return(modify_ldt(func, ptr, bytecount));
}
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+extern int userspace_pid;
+
+int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
+{
+ struct ptrace_ldt ldt;
+ void *buf;
+ int res, n;
+
+ buf = kmalloc(bytecount, GFP_KERNEL);
+ if(buf == NULL)
+ return(-ENOMEM);
+
+ res = 0;
+
+ switch(func){
+ case 1:
+ case 0x11:
+ res = copy_from_user(buf, ptr, bytecount);
+ break;
+ }
+
+ if(res != 0){
+ res = -EFAULT;
+ goto out;
+ }
+
+ ldt = ((struct ptrace_ldt) { .func = func,
+ .ptr = buf,
+ .bytecount = bytecount });
+ res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
+ if(res < 0)
+ goto out;
+
+ switch(func){
+ case 0:
+ case 2:
+ n = res;
+ res = copy_to_user(ptr, buf, n);
+ if(res != 0)
+ res = -EFAULT;
+ else
+ res = n;
+ break;
+ }
+
+ out:
+ kfree(buf);
+ return(res);
+}
+#endif
+
+int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+ return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
+ ptr, bytecount));
+}
+
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index cb47c4e86b1e..817ef7479d3f 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -169,11 +169,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave
}
/*
-b * FXSR floating point environment conversions.
+ * FXSR floating point environment conversions.
*/
-static inline int convert_fxsr_to_user(struct _fpstate *buf,
- struct pt_regs *regs)
+#ifdef CONFIG_MODE_TT
+static inline int convert_fxsr_to_user_tt(struct _fpstate *buf,
+ struct pt_regs *regs)
{
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
unsigned long env[7];
@@ -200,9 +201,17 @@ static inline int convert_fxsr_to_user(struct _fpstate *buf,
}
return 0;
}
+#endif
-static inline int convert_fxsr_from_user(struct pt_regs *regs,
- struct _fpstate *buf)
+static inline int convert_fxsr_to_user(struct _fpstate *buf,
+ struct pt_regs *regs)
+{
+ return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
+}
+
+#ifdef CONFIG_MODE_TT
+static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
+ struct _fpstate *buf)
{
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
unsigned long env[7];
@@ -230,6 +239,13 @@ static inline int convert_fxsr_from_user(struct pt_regs *regs,
}
return 0;
}
+#endif
+
+static inline int convert_fxsr_from_user(struct pt_regs *regs,
+ struct _fpstate *buf)
+{
+ return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
+}
int get_fpregs(unsigned long buf, struct task_struct *child)
{
@@ -251,7 +267,8 @@ int set_fpregs(unsigned long buf, struct task_struct *child)
else return(0);
}
-int get_fpxregs(unsigned long buf, struct task_struct *tsk)
+#ifdef CONFIG_MODE_TT
+int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
{
struct pt_regs *regs = &tsk->thread.regs;
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
@@ -262,8 +279,15 @@ int get_fpxregs(unsigned long buf, struct task_struct *tsk)
if(err) return -EFAULT;
else return 0;
}
+#endif
-int set_fpxregs(unsigned long buf, struct task_struct *tsk)
+int get_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+ return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
+}
+
+#ifdef CONFIG_MODE_TT
+int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
{
struct pt_regs *regs = &tsk->thread.regs;
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
@@ -274,6 +298,12 @@ int set_fpxregs(unsigned long buf, struct task_struct *tsk)
if(err) return -EFAULT;
else return 0;
}
+#endif
+
+int set_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+ return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
+}
#ifdef notdef
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
@@ -291,8 +321,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return(1);
}
#endif
-static inline void copy_fpu_fxsave(struct pt_regs *regs,
- struct user_i387_struct *buf)
+
+#ifdef CONFIG_MODE_TT
+static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
+ struct user_i387_struct *buf)
{
struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
unsigned short *to;
@@ -307,6 +339,13 @@ static inline void copy_fpu_fxsave(struct pt_regs *regs,
memcpy( to, from, 5 * sizeof(unsigned short) );
}
}
+#endif
+
+static inline void copy_fpu_fxsave(struct pt_regs *regs,
+ struct user_i387_struct *buf)
+{
+ (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
+}
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
{
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 659db8a6e2d8..70da62313616 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -102,7 +102,7 @@ void update_debugregs(int seq)
if(seq == debugregs_seq) return;
me = os_getpid();
- tracing_cb(update_debugregs_cb, &me);
+ initial_thread_cb(update_debugregs_cb, &me);
}
/*
diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c
index e61a94651371..6d33bedc07d7 100644
--- a/arch/um/sys-i386/sigcontext.c
+++ b/arch/um/sys-i386/sigcontext.c
@@ -18,45 +18,6 @@ int sc_size(void *data)
return(sizeof(struct sigcontext) + arch->fpstate_size);
}
-int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data)
-{
- struct arch_frame_data *arch = data;
- struct sigcontext *to = to_ptr, *from = from_ptr;
- struct _fpstate *to_fp, *from_fp;
- int err;
-
- to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
- from_fp = from->fpstate;
- err = copy_to_user_proc(to, from, sizeof(*to));
- if(from_fp != NULL){
- err |= copy_to_user_proc(&to->fpstate, &to_fp,
- sizeof(to->fpstate));
- err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
- }
- return(err);
-}
-
-int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data)
-{
- struct arch_frame_data *arch = data;
- struct sigcontext *to = to_ptr, *from = from_ptr;
- struct _fpstate *to_fp, *from_fp;
- unsigned long sigs;
- int err;
-
- to_fp = to->fpstate;
- from_fp = from->fpstate;
- sigs = to->oldmask;
- err = copy_from_user_proc(to, from, sizeof(*to));
- to->oldmask = sigs;
- if(to_fp != NULL){
- err |= copy_from_user_proc(&to->fpstate, &to_fp,
- sizeof(to->fpstate));
- err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
- }
- return(err);
-}
-
void sc_to_sc(void *to_ptr, void *from_ptr)
{
struct sigcontext *to = to_ptr, *from = from_ptr;
diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
index 6d7b853a6157..ad3671423d41 100644
--- a/arch/um/sys-i386/util/mk_thread_kern.c
+++ b/arch/um/sys-i386/util/mk_thread_kern.c
@@ -1,7 +1,19 @@
#include "linux/stddef.h"
#include "linux/sched.h"
-int debugreg(void)
+extern void print_head(void);
+extern void print_constant_ptr(char *name, int value);
+extern void print_constant(char *name, char *type, int value);
+extern void print_tail(void);
+
+#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
+
+int main(int argc, char **argv)
{
- return(offsetof(struct task_struct, thread.arch.debugregs));
+ print_head();
+ print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
+ print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
+ print_tail();
+ return(0);
}
+
diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
index 997a02e9b35a..2620cd6aa1f1 100644
--- a/arch/um/sys-i386/util/mk_thread_user.c
+++ b/arch/um/sys-i386/util/mk_thread_user.c
@@ -1,12 +1,30 @@
#include <stdio.h>
-#include <linux/stddef.h>
-#include <asm/user.h>
-extern int debugreg(void);
+void print_head(void)
+{
+ printf("/*\n");
+ printf(" * Generated by mk_thread\n");
+ printf(" */\n");
+ printf("\n");
+ printf("#ifndef __UM_THREAD_H\n");
+ printf("#define __UM_THREAD_H\n");
+ printf("\n");
+}
+
+void print_constant_ptr(char *name, int value)
+{
+ printf("#define %s(task) ((unsigned long *) "
+ "&(((char *) (task))[%d]))\n", name, value);
+}
+
+void print_constant(char *name, char *type, int value)
+{
+ printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
+ value);
+}
-int main(int argc, char **argv)
+void print_tail(void)
{
- printf("#define TASK_DEBUGREGS(task) ((unsigned long *) "
- "&(((char *) (task))[%d]))\n", debugreg());
- return(0);
+ printf("\n");
+ printf("#endif\n");
}
diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S
index c15bc24842c3..736df4695129 100644
--- a/arch/um/uml.lds.S
+++ b/arch/um/uml.lds.S
@@ -38,6 +38,7 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ . = ALIGN(64);
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
@@ -58,18 +59,27 @@ SECTIONS
__uml_setup_start = .;
.uml.setup.init : { *(.uml.setup.init) }
__uml_setup_end = .;
+
__uml_help_start = .;
.uml.help.init : { *(.uml.help.init) }
__uml_help_end = .;
+
__uml_postsetup_start = .;
.uml.postsetup.init : { *(.uml.postsetup.init) }
__uml_postsetup_end = .;
+
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
+
+ __start___param = .;
+ __param : { *(__param) }
+ __stop___param = .;
+
__per_cpu_start = . ;
.data.percpu : { *(.data.percpu) }
- __per_cpu_end = . ;
+ __per_cpu_end = . ;
+
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile
index 1a59751c61e0..a595641bed1b 100644
--- a/arch/um/util/Makefile
+++ b/arch/um/util/Makefile
@@ -1,4 +1,4 @@
-EXTRA_TARGETS := mk_task mk_task_kern.o
+EXTRA_TARGETS := mk_task mk_constants
$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o
$(CC) -o $@ $^
@@ -6,6 +6,15 @@ $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o
$(obj)/mk_task_user.o: $(src)/mk_task_user.c
$(CC) -o $@ -c $<
+$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o
+ $(CC) -o $@ $^
+
+$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c
+ $(CC) -c $< -o $@
+
+$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
clean:
$(RM) $(EXTRA_TARGETS)
diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
new file mode 100644
index 000000000000..7e74934318c4
--- /dev/null
+++ b/arch/um/util/mk_constants_kern.c
@@ -0,0 +1,24 @@
+#include "linux/kernel.h"
+#include "linux/stringify.h"
+#include "asm/page.h"
+
+extern void print_head(void);
+extern void print_constant_str(char *name, char *value);
+extern void print_constant_int(char *name, int value);
+extern void print_tail(void);
+
+int main(int argc, char **argv)
+{
+ print_head();
+ print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
+ print_constant_str("UM_KERN_EMERG", KERN_EMERG);
+ print_constant_str("UM_KERN_ALERT", KERN_ALERT);
+ print_constant_str("UM_KERN_CRIT", KERN_CRIT);
+ print_constant_str("UM_KERN_ERR", KERN_ERR);
+ print_constant_str("UM_KERN_WARNING", KERN_WARNING);
+ print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
+ print_constant_str("UM_KERN_INFO", KERN_INFO);
+ print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
+ print_tail();
+ return(0);
+}
diff --git a/arch/um/util/mk_constants_user.c b/arch/um/util/mk_constants_user.c
new file mode 100644
index 000000000000..8f4d7e50be7c
--- /dev/null
+++ b/arch/um/util/mk_constants_user.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+
+void print_head(void)
+{
+ printf("/*\n");
+ printf(" * Generated by mk_constants\n");
+ printf(" */\n");
+ printf("\n");
+ printf("#ifndef __UM_CONSTANTS_H\n");
+ printf("#define __UM_CONSTANTS_H\n");
+ printf("\n");
+}
+
+void print_constant_str(char *name, char *value)
+{
+ printf("#define %s \"%s\"\n", name, value);
+}
+
+void print_constant_int(char *name, int value)
+{
+ printf("#define %s %d\n", name, value);
+}
+
+void print_tail(void)
+{
+ printf("\n");
+ printf("#endif\n");
+}
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 91472e7f99f7..13f7e51be1b3 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -672,6 +672,7 @@ source "drivers/usb/Kconfig"
source "net/bluetooth/Kconfig"
+source "arch/x86_64/oprofile/Kconfig"
menu "Kernel hacking"
@@ -728,7 +729,6 @@ config INIT_DEBUG
config KALLSYMS
bool "Load all symbols for debugging/kksymoops"
- depends on DEBUG_KERNEL
help
Say Y here to let the kernel print out symbolic crash information and
symbolic stack backtraces. This increases the size of the kernel
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index ac9649fd9b87..05f428f6a8cf 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -54,6 +54,8 @@ libs-y += arch/x86_64/lib/
core-y += arch/x86_64/kernel/ arch/x86_64/mm/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
+# FIXME: is drivers- right ?
+drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/x86_64/boot $(1)
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index b81e05baff84..2d234181b61b 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -47,6 +47,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
$(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
+ @echo 'Kernel: $@ is ready'
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 864d6aa2ba60..e628de000df2 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -470,6 +470,7 @@ CONFIG_RTC=y
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_AGP_GART is not set
+# CONFIG_AGP3 is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
CONFIG_RAW_DRIVER=y
@@ -586,6 +587,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_BT is not set
#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
# Kernel hacking
#
CONFIG_DEBUG_KERNEL=y
diff --git a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
index 457a337a43c4..0fa49b5c536a 100644
--- a/arch/x86_64/ia32/Makefile
+++ b/arch/x86_64/ia32/Makefile
@@ -6,4 +6,4 @@ export-objs := ia32_ioctl.o sys_ia32.o
obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \
ia32_signal.o \
- ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o
+ ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o syscall32.o
diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c
index ab476cbb12c9..0528b55b42d5 100644
--- a/arch/x86_64/ia32/fpu32.c
+++ b/arch/x86_64/ia32/fpu32.c
@@ -70,10 +70,6 @@ static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
return ret;
}
-struct s10 {
- u64 a;
- u16 b;
-} __attribute__((packed));
static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
struct _fpstate_ia32 *buf)
@@ -98,9 +94,7 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
to = (struct _fpxreg *)&fxsave->st_space[0];
from = &buf->_st[0];
for (i = 0 ; i < 8 ; i++, to++, from++) {
- struct s10 *top = (void *)to, *fromp = (void *)from;
- if (__put_user(fromp->a, &top->a) ||
- __put_user(fromp->b, &top->b))
+ if (__copy_from_user(to, from, sizeof(*from)))
return -1;
}
return 0;
@@ -136,9 +130,7 @@ static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf,
to = &buf->_st[0];
from = (struct _fpxreg *) &fxsave->st_space[0];
for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
- struct s10 *top = (void *)top, *fromp = (void *)from;
- if (__get_user(fromp->a, &top->a) ||
- __get_user(fromp->b, &top->b))
+ if (__copy_to_user(to, from, sizeof(*to)))
return -1;
}
return 0;
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 3fd8ae63faaf..be9f9da4bb2d 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -23,6 +23,12 @@
#include <asm/uaccess.h>
#include <asm/ia32.h>
+#define ELF_NAME "elf/i386"
+
+#define AT_SYSINFO 32
+
+#define ARCH_DLINFO NEW_AUX_ENT(AT_SYSINFO, 0xffffe000)
+
struct file;
struct elf_phdr;
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 002940247a7f..b5f238bc5533 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -2,8 +2,6 @@
* Compatibility mode system call entry point for x86-64.
*
* Copyright 2000-2002 Andi Kleen, SuSE Labs.
- *
- * $Id: ia32entry.S,v 1.31 2002/03/24 13:01:45 ak Exp $
*/
#include <asm/calling.h>
@@ -15,19 +13,21 @@
#include <asm/segment.h>
#include <linux/linkage.h>
- .macro IA32_ARG_FIXUP
+ .macro IA32_ARG_FIXUP noebp=0
movl %edi,%r8d
+ .if \noebp
+ .else
movl %ebp,%r9d
+ .endif
xchg %ecx,%esi
movl %ebx,%edi
movl %edx,%edx /* zero extension */
.endm
/*
- * 32bit SYSCALL instruction entry. This is called from the 32bit vsyscall page.
- *
- * Register setup:
+ * 32bit SYSCALL instruction entry.
*
+ * Arguments:
* %eax System call number.
* %ebx Arg1
* %ecx return EIP
@@ -53,40 +53,51 @@ ENTRY(ia32_cstar_target)
movl %eax,%eax /* zero extension */
movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
movq %rcx,RIP-ARGOFFSET(%rsp)
+ movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */
movl %ebp,%ecx
movq $__USER32_CS,CS-ARGOFFSET(%rsp)
movq $__USER32_DS,SS-ARGOFFSET(%rsp)
movq %r11,EFLAGS-ARGOFFSET(%rsp)
movq %r8,RSP-ARGOFFSET(%rsp)
- /* no need to do an access_ok check here because the 32bit
- user space cannot set r8 to a value > 4GB and the kernel has no
- memory mapping in the first 4GB. */
+ /* no need to do an access_ok check here because r8 has been
+ 32bit zero extended */
/* hardware stack frame is complete now */
-1: movl (%r8),%ebp
+1: movl (%r8),%r9d
.section __ex_table,"a"
.quad 1b,cstar_badarg
.previous
+ movq %r9,R9-ARGOFFSET(%rsp)
GET_THREAD_INFO(%r10)
bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
jc ia32_tracesys
+cstar_do_call:
cmpl $IA32_NR_syscalls,%eax
jae ia32_badsys
- IA32_ARG_FIXUP
+ IA32_ARG_FIXUP 1
call *ia32_sys_call_table(,%rax,8)
- .globl ia32_sysret
+ .globl cstar_sysret
cstar_sysret:
movq %rax,RAX-ARGOFFSET(%rsp)
GET_THREAD_INFO(%r10)
cli
- testl $_TIF_WORK_MASK,threadinfo_flags(%r10)
+ testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
jnz int_ret_from_sys_call
- RESTORE_ARGS 1,0,1,1 /* could avoid the stack restore here */
- movl RIP-SWFRAME(%rsp),%ecx
- movl RSP-SWFRAME(%rsp),%esp
- movl EFLAGS-SWFRAME(%rsp),%r11d
+ RESTORE_ARGS 1,-ARG_SKIP,1,1
+ movl RIP-ARGOFFSET(%rsp),%ecx
+ movl EFLAGS-ARGOFFSET(%rsp),%r11d
+ movl RSP-ARGOFFSET(%rsp),%esp
swapgs
sysretl
+cstar_tracesys:
+ SAVE_REST
+ movq $-ENOSYS,RAX(%rsp) /* really needed? */
+ movq %rsp,%rdi /* &pt_regs -> arg1 */
+ call syscall_trace
+ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
+ RESTORE_REST
+ jmp cstar_do_call
+
cstar_badarg:
movq $-EFAULT,%rax
jmp cstar_sysret
@@ -115,8 +126,11 @@ cstar_badarg:
ENTRY(ia32_syscall)
swapgs
sti
+ movl %eax,%eax
pushq %rax
cld
+ /* note the registers are not zero extended to the sf.
+ this could be a problem */
SAVE_ARGS
GET_THREAD_INFO(%r10)
bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 24b33f75bfb5..3d9ef0ff67ce 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -86,6 +86,11 @@
extern int overflowuid,overflowgid;
+extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
+extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
+extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
+
+
int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf)
{
if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
new file mode 100644
index 000000000000..f0d45a725064
--- /dev/null
+++ b/arch/x86_64/ia32/syscall32.c
@@ -0,0 +1,64 @@
+/* Copyright 2002 Andi Kleen, SuSE Labs */
+
+/* vsyscall handling for 32bit processes. Map a stub page into it
+ on demand because 32bit cannot reach the kernel's fixmaps */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <asm/proto.h>
+#include <asm/tlbflush.h>
+
+/* 32bit SYSCALL stub mapped into user space. */
+asm(" .code32\n"
+ "\nsyscall32:\n"
+ " pushl %ebp\n"
+ " movl %ecx,%ebp\n"
+ " syscall\n"
+ " popl %ebp\n"
+ " ret\n"
+ "syscall32_end:\n"
+ " .code64\n");
+
+extern unsigned char syscall32[], syscall32_end[];
+
+static unsigned long syscall32_page;
+
+/* RED-PEN: This knows too much about high level VM */
+/* Alternative would be to generate a vma with appropiate backing options
+ and let it be handled by generic VM */
+int map_syscall32(struct mm_struct *mm, unsigned long address)
+{
+ pte_t *pte;
+ int err = 0;
+ down_read(&mm->mmap_sem);
+ spin_lock(&mm->page_table_lock);
+ pmd_t *pmd = pmd_alloc(mm, pgd_offset(mm, address), address);
+ if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) {
+ if (pte_none(*pte)) {
+ set_pte(pte,
+ mk_pte(virt_to_page(syscall32_page),
+ PAGE_KERNEL_VSYSCALL));
+ }
+ /* Flush only the local CPU. Other CPUs taking a fault
+ will just end up here again */
+ __flush_tlb_one(address);
+ } else
+ err = -ENOMEM;
+ spin_unlock(&mm->page_table_lock);
+ up_read(&mm->mmap_sem);
+ return err;
+}
+
+static int __init init_syscall32(void)
+{
+ syscall32_page = get_zeroed_page(GFP_KERNEL);
+ if (!syscall32_page)
+ panic("Cannot allocate syscall32 page");
+ SetPageReserved(virt_to_page(syscall32_page));
+ memcpy((void *)syscall32_page, syscall32, syscall32_end - syscall32);
+}
+
+__initcall(init_syscall32);
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index e5b573273dd8..61d5387df48c 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -9,7 +9,7 @@ export-objs := x8664_ksyms.o pci-gart.o pci-dma.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \
- setup64.o bluesmoke.o bootflag.o e820.o reboot.o profile.o
+ setup64.o bluesmoke.o bootflag.o e820.o reboot.o
obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_X86_MSR) += msr.o
@@ -24,6 +24,8 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o
obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_PROFILING) += profile.o
+
$(obj)/bootflag.c:
@ln -sf ../../i386/kernel/bootflag.c $(obj)/bootflag.c
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index d1effba49185..f56ca7829a82 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -987,6 +987,7 @@ asmlinkage void smp_spurious_interrupt(void)
printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
smp_processor_id(), skipped);
last_warning = jiffies;
+ skipped = 0;
} else {
skipped++;
}
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index d7e21aa7eb0a..a2c0878a1c16 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -472,6 +472,11 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_
thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current));
#endif
+ /* Pending single-step? */
+ if (thread_info_flags & _TIF_SINGLESTEP) {
+ regs->eflags |= TF_MASK;
+ clear_thread_flag(TIF_SINGLESTEP);
+ }
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index b1e4cefda410..67d2cf41c2ed 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -222,6 +222,19 @@ static 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,
+ * except when we simulate SMP mode on a uniprocessor system, in that case we
+ * have to call the local interrupt handler.
+ */
+
+#ifndef CONFIG_X86_LOCAL_APIC
+ x86_do_profile(regs);
+#else
+ if (!using_apic_timer)
+ smp_local_timer_interrupt(regs);
+#endif
+
+/*
* If we have an externally synchronized Linux clock, then update CMOS clock
* accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
* closest to exactly 500 ms before the next second. If the update fails, we
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 21b3fbd5330e..46a397e924a3 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -635,7 +635,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
* interface.
*/
if ((regs->cs & 3) == 0)
- goto clear_TF;
+ goto clear_TF_reenable;
if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
goto clear_TF;
}
@@ -653,6 +653,9 @@ clear_dr7:
asm("movq %0,%%db7"::"r"(0UL));
return;
+clear_TF_reenable:
+ set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+
clear_TF:
regs->eflags &= ~TF_MASK;
return;
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index 7d2700fbbedd..2cb3459d0337 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -26,6 +26,7 @@
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/nmi.h>
#include <asm/kdebug.h>
#include <asm/unistd.h>
@@ -116,7 +117,11 @@ EXPORT_SYMBOL_NOVERS(__read_lock_failed);
EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
+#endif
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
+EXPORT_SYMBOL_GPL(set_nmi_pm_callback);
+EXPORT_SYMBOL_GPL(unset_nmi_pm_callback);
#endif
#ifdef CONFIG_VT
@@ -127,6 +132,11 @@ EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(rtc_lock);
+EXPORT_SYMBOL_GPL(register_profile_notifier);
+EXPORT_SYMBOL_GPL(unregister_profile_notifier);
+EXPORT_SYMBOL_GPL(set_nmi_callback);
+EXPORT_SYMBOL_GPL(unset_nmi_callback);
+
/* Export string functions. We normally rely on gcc builtin for most of these,
but gcc sometimes decides not to inline them. */
#undef memcpy
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 5f93c2d6ba2f..00708d1d82e3 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -29,6 +29,7 @@
#include <asm/hardirq.h>
#include <asm/smp.h>
#include <asm/tlbflush.h>
+#include <asm/proto.h>
extern void die(const char *,struct pt_regs *,long);
@@ -211,6 +212,15 @@ bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
+#ifdef CONFIG_IA32_EMULATION
+ /* 32bit vsyscall. map on demand. */
+ if (test_thread_flag(TIF_IA32) &&
+ address >= 0xffffe000 && address < 0xffffefff-7) {
+ if (map_syscall32(mm, address) < 0)
+ goto out_of_memory2;
+ return;
+ }
+#endif
printk("%s[%d] segfault at rip:%lx rsp:%lx adr:%lx err:%lx\n",
tsk->comm, tsk->pid, regs->rip, regs->rsp, address,
error_code);
@@ -263,6 +273,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
+out_of_memory2:
if (current->pid == 1) {
yield();
goto again;
@@ -300,9 +311,6 @@ vmalloc_fault:
pmd_t *pmd;
pte_t *pte;
- printk("vmalloc_fault err %lx addr %lx rip %lx\n",
- error_code, address, regs->rip);
-
/*
* x86-64 has the same kernel 3rd level pages for all CPUs.
* But for vmalloc/modules the TLB synchronization works lazily,
diff --git a/arch/x86_64/oprofile/Kconfig b/arch/x86_64/oprofile/Kconfig
new file mode 100644
index 000000000000..5ade19801b97
--- /dev/null
+++ b/arch/x86_64/oprofile/Kconfig
@@ -0,0 +1,23 @@
+
+menu "Profiling support"
+ depends on EXPERIMENTAL
+
+config PROFILING
+ bool "Profiling support (EXPERIMENTAL)"
+ help
+ Say Y here to enable the extended profiling support mechanisms used
+ by profilers such as OProfile.
+
+
+config OPROFILE
+ tristate "OProfile system profiling (EXPERIMENTAL)"
+ depends on PROFILING
+ help
+ OProfile is a profiling system capable of profiling the
+ whole system, include the kernel, kernel modules, libraries,
+ and applications.
+
+ If unsure, say N.
+
+endmenu
+
diff --git a/arch/x86_64/oprofile/Makefile b/arch/x86_64/oprofile/Makefile
new file mode 100644
index 000000000000..ab145c3f81c5
--- /dev/null
+++ b/arch/x86_64/oprofile/Makefile
@@ -0,0 +1,33 @@
+#
+# oprofile for x86-64.
+# Just reuse the one from i386. The Hammer performance counters
+# are similar to Athlon.
+#
+
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+ oprof.o cpu_buffer.o buffer_sync.o \
+ event_buffer.o oprofile_files.o \
+ oprofilefs.o oprofile_stats.o )
+
+oprofile-objs := $(DRIVER_OBJS) init.o timer_int.o
+
+oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o
+
+INCL := $(obj)/op_counter.h $(obj)/op_x86_model.h
+
+$(obj)/nmi_int.c: ${INCL}
+ @ln -sf ../../i386/oprofile/nmi_int.c $(obj)/nmi_int.c
+$(obj)/op_model_athlon.c: ${INCL}
+ @ln -sf ../../i386/oprofile/op_model_athlon.c $(obj)/op_model_athlon.c
+$(obj)/init.c: ${INCL}
+ @ln -sf ../../i386/oprofile/init.c $(obj)/init.c
+$(obj)/timer_int.c: ${INCL}
+ @ln -sf ../../i386/oprofile/timer_int.c $(obj)/timer_int.c
+$(obj)/op_counter.h:
+ @ln -sf ../../i386/oprofile/op_counter.h $(obj)/op_counter.h
+$(obj)/op_x86_model.h:
+ @ln -sf ../../i386/oprofile/op_x86_model.h $(obj)/op_x86_model.h
+clean-files += op_x86_model.h op_counter.h timer_int.c init.c \
+ op_model_athlon.c nmi_int.c
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 2a3b46773d88..958ef4898971 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -493,8 +493,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, i
acsi_delay_end(COMMAND_DELAY);
DISABLE_IRQ();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Low on A1 */
dma_wd.dma_mode_status = 0x88 | rwflag;
MFPDELAY();
@@ -511,7 +510,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, i
else
dma_wd.dma_hi = (unsigned char)paddr;
MFPDELAY();
- restore_flags(flags);
+ local_irq_restore(flags);
/* send the command bytes except the last */
for( i = 0; i < 5; ++i ) {
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 7ca90514abf0..918b0e8cb287 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -500,12 +500,11 @@ static void slm_test_ready( unsigned long dummy )
int did_wait = 0;
#endif
- save_flags(flags);
- cli();
-
+ local_irq_save(flags);
+
addr = get_dma_addr();
if ((d = SLMEndAddr - addr) > 0) {
- restore_flags(flags);
+ local_irq_restore(flags);
/* slice not yet finished, decide whether to start another timer or to
* busy-wait */
@@ -523,7 +522,7 @@ static void slm_test_ready( unsigned long dummy )
do_gettimeofday( &start_tm );
did_wait = 1;
#endif
- cli();
+ local_irq_disable();
while( get_dma_addr() < SLMEndAddr )
barrier();
}
@@ -547,7 +546,7 @@ static void slm_test_ready( unsigned long dummy )
DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 );
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
#ifdef DEBUG
if (did_wait) {
@@ -584,10 +583,9 @@ static void slm_test_ready( unsigned long dummy )
static void set_dma_addr( unsigned long paddr )
-{ unsigned long flags;
-
- save_flags(flags);
- cli();
+{ unsigned long flags;
+
+ local_irq_save(flags);
dma_wd.dma_lo = (unsigned char)paddr;
paddr >>= 8;
MFPDELAY();
@@ -599,7 +597,7 @@ static void set_dma_addr( unsigned long paddr )
else
dma_wd.dma_hi = (unsigned char)paddr;
MFPDELAY();
- restore_flags(flags);
+ local_irq_restore(flags);
}
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index f28d18733af5..85728c00645f 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -72,6 +72,7 @@
#include <linux/amifd.h>
#include <linux/ioport.h>
#include <linux/buffer_head.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -228,12 +229,11 @@ static void ms_delay(int ms)
unsigned long flags;
int ticks;
if (ms > 0) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
while (ms_busy == 0)
sleep_on(&ms_wait);
ms_busy = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
ticks = MS_TICKS*ms-1;
ciaa.tblo=ticks%256;
ciaa.tbhi=ticks/256;
@@ -259,13 +259,12 @@ static void get_fdc(int drive)
#ifdef DEBUG
printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested);
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
while (!try_fdc(drive))
sleep_on(&fdc_wait);
fdc_busy = drive;
fdc_nested++;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static inline void rel_fdc(void)
@@ -321,8 +320,7 @@ static void fd_deselect (int drive)
}
get_fdc(drive);
- save_flags (flags);
- sti();
+ local_irq_save(flags);
selected = -1;
@@ -330,7 +328,7 @@ static void fd_deselect (int drive)
prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
ciab.prb = prb;
- restore_flags (flags);
+ local_irq_restore (flags);
rel_fdc();
}
@@ -1305,10 +1303,9 @@ static int non_int_flush_track (unsigned long nr)
rel_fdc();
return 0;
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (writepending != 2) {
- restore_flags(flags);
+ local_irq_restore(flags);
(*unit[nr].dtype->write_fkt)(nr);
if (!raw_write(nr)) {
printk (KERN_NOTICE "floppy disk write protected "
@@ -1320,7 +1317,7 @@ static int non_int_flush_track (unsigned long nr)
sleep_on (&wait_fd_block);
}
else {
- restore_flags(flags);
+ local_irq_restore(flags);
ms_delay(2); /* 2 ms post_write delay */
post_write(nr);
}
@@ -1428,8 +1425,7 @@ static void redo_fd_request(void)
* setup a callback to write the track buffer
* after a short (1 tick) delay.
*/
- save_flags (flags);
- cli();
+ local_irq_save(flags);
floppy->dirty = 1;
/* reset the timer */
@@ -1437,7 +1433,7 @@ static void redo_fd_request(void)
flush_track_timer[drive].expires = jiffies + 1;
add_timer (flush_track_timer + drive);
- restore_flags (flags);
+ local_irq_restore(flags);
break;
}
}
@@ -1606,15 +1602,14 @@ static int floppy_open(struct inode *inode, struct file *filp)
}
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
fd_ref[drive]++;
fd_device[drive] = system;
#ifdef MODULE
if (unit[drive].motor == 0)
MOD_INC_USE_COUNT;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
if (old_dev != system)
invalidate_buffers(mk_kdev(FLOPPY_MAJOR, drive + (system << 2)));
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index d4d03d9a6a1d..c9dc16a8059e 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -248,24 +248,24 @@ static struct atari_floppy_struct {
#define FDC_READ(reg) ({ \
/* unsigned long __flags; */ \
unsigned short __val; \
- /* save_flags(__flags); cli(); */ \
+ /* local_irq_save(__flags); */ \
dma_wd.dma_mode_status = 0x80 | (reg); \
udelay(25); \
__val = dma_wd.fdc_acces_seccount; \
MFPDELAY(); \
- /* restore_flags(__flags); */ \
+ /* local_irq_restore(__flags); */ \
__val & 0xff; \
})
#define FDC_WRITE(reg,val) \
do { \
/* unsigned long __flags; */ \
- /* save_flags(__flags); cli(); */ \
+ /* local_irq_save(__flags); */ \
dma_wd.dma_mode_status = 0x80 | (reg); \
udelay(25); \
dma_wd.fdc_acces_seccount = (val); \
MFPDELAY(); \
- /* restore_flags(__flags); */ \
+ /* local_irq_restore(__flags); */ \
} while(0)
@@ -394,7 +394,7 @@ static int floppy_release( struct inode * inode, struct file * filp );
static struct timer_list motor_off_timer =
TIMER_INITIALIZER(fd_motor_off_timer, 0, 0);
-static struct timer_list readtrack_timer
+static struct timer_list readtrack_timer =
TIMER_INITIALIZER(fd_readtrack_check, 0, 0);
static struct timer_list timeout_timer =
@@ -434,14 +434,14 @@ static void fd_select_side( int side )
{
unsigned long flags;
- save_flags(flags);
- cli(); /* protect against various other ints mucking around with the PSG */
+ /* protect against various other ints mucking around with the PSG */
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0x01 :
sound_ym.rd_data_reg_sel & 0xfe;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -457,13 +457,13 @@ static void fd_select_drive( int drive )
if (drive == SelectedDrive)
return;
- save_flags(flags);
- cli(); /* protect against various other ints mucking around with the PSG */
+ /* protect against various other ints mucking around with the PSG */
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
tmp = sound_ym.rd_data_reg_sel;
sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1);
atari_dont_touch_floppy_select = 1;
- restore_flags(flags);
+ local_irq_restore(flags);
/* restore track register to saved value */
FDC_WRITE( FDCREG_TRACK, UD.track );
@@ -484,8 +484,8 @@ static void fd_deselect( void )
{
unsigned long flags;
- save_flags(flags);
- cli(); /* protect against various other ints mucking around with the PSG */
+ /* protect against various other ints mucking around with the PSG */
+ local_irq_save(flags);
atari_dont_touch_floppy_select = 0;
sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
sound_ym.wd_data = (sound_ym.rd_data_reg_sel |
@@ -493,7 +493,7 @@ static void fd_deselect( void )
/* On Falcon, the drive B select line is used on the printer port, so
* leave it alone... */
SelectedDrive = -1;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -549,8 +549,8 @@ static void check_change( unsigned long dummy )
if (++drive > 1 || !UD.connected)
drive = 0;
- save_flags(flags);
- cli(); /* protect against various other ints mucking around with the PSG */
+ /* protect against various other ints mucking around with the PSG */
+ local_irq_save(flags);
if (!stdma_islocked()) {
sound_ym.rd_data_reg_sel = 14;
@@ -566,7 +566,7 @@ static void check_change( unsigned long dummy )
set_bit (drive, &changed_floppies);
}
}
- restore_flags(flags);
+ local_irq_restore(flags);
start_check_change_timer();
}
@@ -666,13 +666,12 @@ static int do_format(kdev_t device, struct atari_format_descr *desc)
DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
drive, desc->track, desc->head, desc->sect_offset ));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
while( fdc_busy ) sleep_on( &fdc_wait );
fdc_busy = 1;
stdma_lock(floppy_irq, NULL);
atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
- restore_flags(flags);
+ local_irq_restore(flags);
type = minor(device) >> 2;
if (type) {
@@ -930,8 +929,7 @@ static void fd_rwsec( void )
udelay(25);
/* Setup DMA */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
dma_wd.dma_lo = (unsigned char)paddr;
MFPDELAY();
paddr >>= 8;
@@ -943,7 +941,7 @@ static void fd_rwsec( void )
else
dma_wd.dma_hi = (unsigned char)paddr;
MFPDELAY();
- restore_flags(flags);
+ local_irq_restore(flags);
/* Clear FIFO and switch DMA to correct mode */
dma_wd.dma_mode_status = 0x90 | rwflag;
@@ -990,8 +988,7 @@ static void fd_readtrack_check( unsigned long dummy )
{
unsigned long flags, addr, addr2;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!MultReadInProgress) {
/* This prevents a race condition that could arise if the
@@ -1000,7 +997,7 @@ static void fd_readtrack_check( unsigned long dummy )
* already cleared 'MultReadInProgress' when flow of control
* gets here.
*/
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -1026,7 +1023,7 @@ static void fd_readtrack_check( unsigned long dummy )
*/
SET_IRQ_HANDLER( NULL );
MultReadInProgress = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
DPRINT(("fd_readtrack_check(): done\n"));
FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
udelay(25);
@@ -1038,7 +1035,7 @@ static void fd_readtrack_check( unsigned long dummy )
}
else {
/* not yet finished, wait another tenth rotation */
- restore_flags(flags);
+ local_irq_restore(flags);
DPRINT(("fd_readtrack_check(): not yet finished\n"));
mod_timer(&readtrack_timer, jiffies + HZ/5/10);
}
@@ -1199,8 +1196,7 @@ static void fd_writetrack( void )
udelay(40);
/* Setup DMA */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
dma_wd.dma_lo = (unsigned char)paddr;
MFPDELAY();
paddr >>= 8;
@@ -1212,7 +1208,7 @@ static void fd_writetrack( void )
else
dma_wd.dma_hi = (unsigned char)paddr;
MFPDELAY();
- restore_flags(flags);
+ local_irq_restore(flags);
/* Clear FIFO and switch DMA to correct mode */
dma_wd.dma_mode_status = 0x190;
@@ -1325,12 +1321,11 @@ static void finish_fdc_done( int dummy )
start_check_change_timer();
start_motor_off_timer();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
stdma_release();
fdc_busy = 0;
wake_up( &fdc_wait );
- restore_flags(flags);
+ local_irq_restore(flags);
DPRINT(("finish_fdc() finished\n"));
}
@@ -1519,10 +1514,10 @@ void do_fd_request(request_queue_t * q)
stdma_lock(floppy_irq, NULL);
atari_disable_irq( IRQ_MFP_FDC );
- save_flags(flags); /* The request function is called with ints
- sti(); * disabled... so must save the IPL for later */
+ local_save_flags(flags); /* The request function is called with ints
+ local_irq_disable(); * disabled... so must save the IPL for later */
redo_fd_request();
- restore_flags(flags);
+ local_irq_restore(flags);
atari_enable_irq( IRQ_MFP_FDC );
}
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 18e8548bfcdb..755fc9c3a81f 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -209,17 +209,16 @@ static void swimiop_init_request(struct swim_iop_req *req)
static int swimiop_send_request(struct swim_iop_req *req)
{
- unsigned long cpu_flags;
+ unsigned long flags;
int err;
/* It's doubtful an interrupt routine would try to send */
/* a SWIM request, but I'd rather play it safe here. */
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
if (current_req != NULL) {
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
return -ENOMEM;
}
@@ -227,7 +226,7 @@ static int swimiop_send_request(struct swim_iop_req *req)
/* Interrupts should be back on for iop_send_message() */
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req,
sizeof(req->command), (__u8 *) &req->command[0],
@@ -423,14 +422,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (fs->state != idle) {
++fs->wanted;
while (fs->state != available) {
if (interruptible && signal_pending(current)) {
--fs->wanted;
- restore_flags(flags);
+ local_irq_restore(flags);
return -EINTR;
}
interruptible_sleep_on(&fs->wait);
@@ -438,7 +436,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
--fs->wanted;
}
fs->state = state;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -446,11 +444,10 @@ static void release_drive(struct floppy_state *fs)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
fs->state = idle;
start_request(fs);
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void set_timeout(struct floppy_state *fs, int nticks,
@@ -458,7 +455,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
{
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (fs->timeout_pending)
del_timer(&fs->timeout);
init_timer(&fs->timeout);
@@ -467,7 +464,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
fs->timeout.data = (unsigned long) fs;
add_timer(&fs->timeout);
fs->timeout_pending = 1;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void do_fd_request(request_queue_t * q)
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 80096fad0c32..263772c3ae1a 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -73,8 +73,6 @@ static struct gendisk *z2ram_gendisk;
static void do_z2_request(request_queue_t *q)
{
- u_long start, len, addr, size;
-
while (!blk_queue_empty(q)) {
struct request *req = elv_next_request(q);
unsigned long start = req->sector << 9;
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 79ac0284783e..ed775912bac9 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -213,7 +213,7 @@ static void rs_stop(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_stop"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
/* disable Tx interrupt and remove any pending interrupts */
@@ -222,7 +222,7 @@ static void rs_stop(struct tty_struct *tty)
custom.intreq = IF_TBE;
mb();
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_start(struct tty_struct *tty)
@@ -233,7 +233,7 @@ static void rs_start(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_start"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->xmit.head != info->xmit.tail
&& info->xmit.buf
&& !(info->IER & UART_IER_THRI)) {
@@ -244,7 +244,7 @@ static void rs_start(struct tty_struct *tty)
custom.intreq = IF_SETCLR | IF_TBE;
mb();
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -601,7 +601,7 @@ static int startup(struct async_struct * info)
if (!page)
return -ENOMEM;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
@@ -672,11 +672,11 @@ static int startup(struct async_struct * info)
change_speed(info, 0);
info->flags |= ASYNC_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
errout:
- restore_flags(flags);
+ local_irq_restore(flags);
return retval;
}
@@ -698,7 +698,7 @@ static void shutdown(struct async_struct * info)
printk("Shutting down serial port %d ....\n", info->line);
#endif
- save_flags(flags); cli(); /* Disable interrupts */
+ local_irq_save(flags); /* Disable interrupts */
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -734,7 +734,7 @@ static void shutdown(struct async_struct * info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -862,7 +862,7 @@ static void change_speed(struct async_struct *info,
*/
if ((cflag & CREAD) == 0)
info->ignore_status_mask |= UART_LSR_DR;
- save_flags(flags); cli();
+ local_irq_save(flags);
{
short serper;
@@ -880,7 +880,7 @@ static void change_speed(struct async_struct *info,
}
info->LCR = cval; /* Save LCR */
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_put_char(struct tty_struct *tty, unsigned char ch)
@@ -894,17 +894,17 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit.buf)
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) == 0) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
info->xmit.buf[info->xmit.head++] = ch;
info->xmit.head &= SERIAL_XMIT_SIZE-1;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -921,14 +921,14 @@ static void rs_flush_chars(struct tty_struct *tty)
|| !info->xmit.buf)
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
info->IER |= UART_IER_THRI;
custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
custom.intreq = IF_SETCLR | IF_TBE;
mb();
- restore_flags(flags);
+ local_irq_restore(flags);
}
static int rs_write(struct tty_struct * tty, int from_user,
@@ -944,7 +944,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (!tty || !info->xmit.buf || !tmp_buf)
return 0;
- save_flags(flags);
+ local_save_flags(flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
@@ -961,7 +961,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
ret = -EFAULT;
break;
}
- cli();
+ local_irq_disable();
c1 = CIRC_SPACE_TO_END(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE);
@@ -970,14 +970,14 @@ static int rs_write(struct tty_struct * tty, int from_user,
memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
- restore_flags(flags);
+ local_irq_restore(flags);
buf += c;
count -= c;
ret += c;
}
up(&tmp_buf_sem);
} else {
- cli();
+ local_irq_disable();
while (1) {
c = CIRC_SPACE_TO_END(info->xmit.head,
info->xmit.tail,
@@ -994,20 +994,20 @@ static int rs_write(struct tty_struct * tty, int from_user,
count -= c;
ret += c;
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (info->xmit.head != info->xmit.tail
&& !tty->stopped
&& !tty->hw_stopped
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
- cli();
+ local_irq_disable();
custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
custom.intreq = IF_SETCLR | IF_TBE;
mb();
- restore_flags(flags);
+ local_irq_restore(flags);
}
return ret;
}
@@ -1037,9 +1037,9 @@ static void rs_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
info->xmit.head = info->xmit.tail = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
@@ -1063,8 +1063,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
/* Make sure transmit interrupts are on */
/* Check this ! */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if(!(custom.intenar & IF_TBE)) {
custom.intena = IF_SETCLR | IF_TBE;
mb();
@@ -1072,7 +1071,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
custom.intreq = IF_SETCLR | IF_TBE;
mb();
}
- restore_flags(flags);
+ local_irq_restore(flags);
info->IER |= UART_IER_THRI;
}
@@ -1106,9 +1105,9 @@ static void rs_throttle(struct tty_struct * tty)
if (tty->termios->c_cflag & CRTSCTS)
info->MCR &= ~SER_RTS;
- save_flags(flags); cli();
+ local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_unthrottle(struct tty_struct * tty)
@@ -1133,9 +1132,9 @@ static void rs_unthrottle(struct tty_struct * tty)
}
if (tty->termios->c_cflag & CRTSCTS)
info->MCR |= SER_RTS;
- save_flags(flags); cli();
+ local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -1256,10 +1255,10 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
unsigned int result;
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
status = custom.serdatr;
mb();
- restore_flags(flags);
+ local_irq_restore(flags);
result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -1274,9 +1273,9 @@ static int get_modem_info(struct async_struct * info, unsigned int *value)
unsigned long flags;
control = info->MCR;
- save_flags(flags); cli();
+ local_irq_save(flags);
status = ciab.pra;
- restore_flags(flags);
+ local_irq_restore(flags);
result = ((control & SER_RTS) ? TIOCM_RTS : 0)
| ((control & SER_DTR) ? TIOCM_DTR : 0)
| (!(status & SER_DCD) ? TIOCM_CAR : 0)
@@ -1317,9 +1316,9 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
default:
return -EINVAL;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -1334,13 +1333,13 @@ static void rs_break(struct tty_struct *tty, int break_state)
if (serial_paranoia_check(info, tty->device, "rs_break"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (break_state == -1)
custom.adkcon = AC_SETCLR | AC_UARTBRK;
else
custom.adkcon = AC_UARTBRK;
mb();
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1394,18 +1393,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- save_flags(flags); cli();
+ local_irq_save(flags);
/* note the counters on entry */
cprev = info->state->icount;
- restore_flags(flags);
+ local_irq_restore(flags);
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
- save_flags(flags); cli();
+ local_irq_save(flags);
cnow = info->state->icount; /* atomic copy */
- restore_flags(flags);
+ local_irq_restore(flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
@@ -1426,9 +1425,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
- save_flags(flags); cli();
+ local_irq_save(flags);
cnow = info->state->icount;
- restore_flags(flags);
+ local_irq_restore(flags);
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
@@ -1473,9 +1472,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
if ((old_termios->c_cflag & CBAUD) &&
!(cflag & CBAUD)) {
info->MCR &= ~(SER_DTR|SER_RTS);
- save_flags(flags); cli();
+ local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Handle transition away from B0 status */
@@ -1486,9 +1485,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= SER_RTS;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Handle turning off CRTSCTS */
@@ -1532,12 +1531,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
state = info->state;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -1564,7 +1563,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (state->count) {
DBG_CNT("before DEC-2");
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
info->flags |= ASYNC_CLOSING;
@@ -1624,7 +1623,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
MOD_DEC_USE_COUNT;
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -1797,19 +1796,19 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready before block: ttys%d, count = %d\n",
state->line, state->count);
#endif
- save_flags(flags); cli();
+ local_irq_save(flags);
if (!tty_hung_up_p(filp)) {
extra_count = 1;
state->count--;
}
- restore_flags(flags);
+ local_irq_restore(flags);
info->blocked_open++;
while (1) {
- save_flags(flags); cli();
+ local_irq_save(flags);
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD))
rtsdtr_ctrl(SER_DTR|SER_RTS);
- restore_flags(flags);
+ local_irq_restore(flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
@@ -2009,10 +2008,10 @@ static inline int line_info(char *buf, struct serial_state *state)
info->quot = 0;
info->tty = 0;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
status = ciab.pra;
control = info ? info->MCR : status;
- restore_flags(flags);
+ local_irq_restore(flags);
stat_buf[0] = 0;
stat_buf[1] = 0;
@@ -2207,8 +2206,7 @@ static int __init rs_init(void)
state->baud_base = amiga_colorclock;
state->xmit_fifo_size = 1;
- save_flags (flags);
- cli();
+ local_irq_save(flags);
/* set ISRs, and then disable the rx interrupts */
request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
@@ -2222,7 +2220,7 @@ static int __init rs_init(void)
custom.intreq = IF_RBF | IF_TBE;
mb();
- restore_flags (flags);
+ local_irq_restore(flags);
/*
* set the appropriate directions for the modem control flags,
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 8e373bcbe71b..b8a01d45027d 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -201,10 +201,9 @@ static void a2232_disable_tx_interrupts(void *ptr)
stat->OutDisable = -1;
/* Does this here really have to be? */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
port->gs.flags &= ~GS_TX_INTEN;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void a2232_enable_tx_interrupts(void *ptr)
@@ -218,10 +217,9 @@ static void a2232_enable_tx_interrupts(void *ptr)
stat->OutDisable = 0;
/* Does this here really have to be? */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
port->gs.flags |= GS_TX_INTEN;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void a2232_disable_rx_interrupts(void *ptr)
@@ -252,8 +250,7 @@ static void a2232_shutdown_port(void *ptr)
port = ptr;
stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
port->gs.flags &= ~GS_ACTIVE;
@@ -266,7 +263,7 @@ static void a2232_shutdown_port(void *ptr)
stat->Setup = -1;
}
- restore_flags(flags);
+ local_irq_restore(flags);
/* After analyzing control flow, I think a2232_shutdown_port
is actually the last call from the system when at application
@@ -300,15 +297,14 @@ static int a2232_set_real_termios(void *ptr)
baud = port->gs.baud;
if (baud == 0) {
/* speed == 0 -> drop DTR, do nothing else */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
// Clear DTR (and RTS... mhhh).
status->Command = ( (status->Command & ~A2232CMD_CMask) |
A2232CMD_Close );
status->OutFlush = -1;
status->Setup = -1;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -387,8 +383,7 @@ static int a2232_set_real_termios(void *ptr)
/* Now we have all parameters and can go to set them: */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
status->Param = a2232_param | A2232PARAM_RcvBaud;
status->Command = a2232_cmd | A2232CMD_Open | A2232CMD_Enable;
@@ -396,7 +391,7 @@ static int a2232_set_real_termios(void *ptr)
status->OutDisable = 0;
status->Setup = -1;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index e6d33dc1e8ab..65a8e8438c0a 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -274,18 +274,18 @@ serial_paranoia_check(struct cyclades_port *info, kdev_t device,
void
SP(char *data){
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
console_print(data);
- restore_flags(flags);
+ local_irq_restore(flags);
}
char scrn[2];
void
CP(char data){
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
scrn[0] = data;
console_print(scrn);
- restore_flags(flags);
+ local_irq_restore(flags);
}/* CP */
void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */
@@ -305,7 +305,7 @@ write_cy_cmd(volatile u_char *base_addr, u_char cmd)
unsigned long flags;
volatile int i;
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Check to see that the previous command has completed */
for(i = 0 ; i < 100 ; i++){
if (base_addr[CyCCR] == 0){
@@ -316,13 +316,13 @@ write_cy_cmd(volatile u_char *base_addr, u_char cmd)
/* if the CCR never cleared, the previous command
didn't finish within the "reasonable time" */
if ( i == 10 ) {
- restore_flags(flags);
+ local_irq_restore(flags);
return (-1);
}
/* Issue the new command */
base_addr[CyCCR] = cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
return(0);
} /* write_cy_cmd */
@@ -347,10 +347,10 @@ cy_stop(struct tty_struct *tty)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)(channel); /* index channel */
base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- restore_flags(flags);
+ local_irq_restore(flags);
return;
} /* cy_stop */
@@ -372,10 +372,10 @@ cy_start(struct tty_struct *tty)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)(channel);
base_addr[CyIER] |= CyTxMpty;
- restore_flags(flags);
+ local_irq_restore(flags);
return;
} /* cy_start */
@@ -816,7 +816,7 @@ startup(struct cyclades_port * info)
printk("startup channel %d\n", channel);
#endif
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR);
@@ -838,7 +838,7 @@ startup(struct cyclades_port * info)
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_OPEN
printk(" done\n");
@@ -854,10 +854,10 @@ start_xmit( struct cyclades_port *info )
int channel;
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = channel;
base_addr[CyIER] |= CyTxMpty;
- restore_flags(flags);
+ local_irq_restore(flags);
} /* start_xmit */
/*
@@ -888,7 +888,7 @@ shutdown(struct cyclades_port * info)
Other choices are to delay some fixed interval
or schedule some later processing.
*/
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->xmit_buf){
free_page((unsigned long) info->xmit_buf);
info->xmit_buf = 0;
@@ -912,7 +912,7 @@ shutdown(struct cyclades_port * info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_OPEN
printk(" done\n");
@@ -1079,7 +1079,7 @@ config_setup(struct cyclades_port * info)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CyCMR set once only in mvme167_init_serial() */
@@ -1159,7 +1159,7 @@ config_setup(struct cyclades_port * info)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
- restore_flags(flags);
+ local_irq_restore(flags);
} /* config_setup */
@@ -1180,16 +1180,16 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit_buf)
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->xmit_cnt >= PAGE_SIZE - 1) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= PAGE_SIZE - 1;
info->xmit_cnt++;
- restore_flags(flags);
+ local_irq_restore(flags);
} /* cy_put_char */
@@ -1214,10 +1214,10 @@ cy_flush_chars(struct tty_struct *tty)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = channel;
base_addr[CyIER] |= CyTxMpty;
- restore_flags(flags);
+ local_irq_restore(flags);
} /* cy_flush_chars */
@@ -1262,13 +1262,13 @@ cy_write(struct tty_struct * tty, int from_user,
break;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c;
- restore_flags(flags);
+ local_irq_restore(flags);
buf += c;
count -= c;
@@ -1277,18 +1277,18 @@ cy_write(struct tty_struct * tty, int from_user,
up(&tmp_buf_sem);
} else {
while (1) {
- save_flags(flags); cli();
+ local_irq_save(flags);
c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0) {
- restore_flags(flags);
+ local_irq_restore(flags);
break;
}
memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c;
- restore_flags(flags);
+ local_irq_restore(flags);
buf += c;
count -= c;
@@ -1352,9 +1352,9 @@ cy_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
&& tty->ldisc.write_wakeup)
@@ -1393,10 +1393,10 @@ cy_throttle(struct tty_struct * tty)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
return;
} /* cy_throttle */
@@ -1429,10 +1429,10 @@ cy_unthrottle(struct tty_struct * tty)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = CyRTS;
- restore_flags(flags);
+ local_irq_restore(flags);
return;
} /* cy_unthrottle */
@@ -1514,10 +1514,10 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
channel = info->line;
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
- restore_flags(flags);
+ local_irq_restore(flags);
result = ((status & CyRTS) ? TIOCM_RTS : 0)
| ((status & CyDTR) ? TIOCM_DTR : 0)
@@ -1543,13 +1543,13 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = CyRTS;
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CP('S');CP('2'); */
base_addr[CyMSVR2] = CyDTR;
@@ -1557,18 +1557,18 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
printk("cyc: %d: raising DTR\n", __LINE__);
printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
break;
case TIOCMBIC:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CP('C');CP('2'); */
base_addr[CyMSVR2] = 0;
@@ -1576,23 +1576,23 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
printk("cyc: %d: dropping DTR\n", __LINE__);
printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
break;
case TIOCMSET:
if (arg & TIOCM_RTS){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = CyRTS;
- restore_flags(flags);
+ local_irq_restore(flags);
}else{
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (arg & TIOCM_DTR){
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CP('S');CP('3'); */
base_addr[CyMSVR2] = CyDTR;
@@ -1600,9 +1600,9 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
printk("cyc: %d: raising DTR\n", __LINE__);
printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}else{
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CP('C');CP('3'); */
base_addr[CyMSVR2] = 0;
@@ -1610,7 +1610,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
printk("cyc: %d: dropping DTR\n", __LINE__);
printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
break;
default:
@@ -2060,7 +2060,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
channel = info->line;
while (1) {
- save_flags(flags); cli();
+ local_irq_save(flags);
if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
base_addr[CyCAR] = (u_char)channel;
base_addr[CyMSVR1] = CyRTS;
@@ -2071,7 +2071,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
#endif
}
- restore_flags(flags);
+ local_irq_restore(flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
@@ -2082,17 +2082,17 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
}
break;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
base_addr[CyCAR] = (u_char)channel;
/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
&& !(info->flags & ASYNC_CLOSING)
&& (C_CLOCAL(tty)
|| (base_addr[CyMSVR1] & CyDCD))) {
- restore_flags(flags);
+ local_irq_restore(flags);
break;
}
- restore_flags(flags);
+ local_irq_restore(flags);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
@@ -2238,7 +2238,7 @@ mvme167_serial_console_setup(int cflag)
u_char rcor, rbpr, badspeed = 0;
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
/*
* First probe channel zero of the chip, to see what speed has
@@ -2263,7 +2263,7 @@ mvme167_serial_console_setup(int cflag)
my_udelay(20000L); /* Allow time for any active o/p to complete */
if(base_addr[CyCCR] != 0x00){
- restore_flags(flags);
+ local_irq_restore(flags);
/* printk(" chip is never idle (CCR != 0)\n"); */
return;
}
@@ -2272,7 +2272,7 @@ mvme167_serial_console_setup(int cflag)
my_udelay(1000L);
if(base_addr[CyGFRCR] == 0x00){
- restore_flags(flags);
+ local_irq_restore(flags);
/* printk(" chip is not responding (GFRCR stayed 0)\n"); */
return;
}
@@ -2331,7 +2331,7 @@ mvme167_serial_console_setup(int cflag)
base_addr[CyIER] = CyRxData;
write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR);
- restore_flags(flags);
+ local_irq_restore(flags);
my_udelay(20000L); /* Let it all settle down */
@@ -2606,7 +2606,7 @@ show_status(int line_num)
info->session, info->pgrp, (long)info->open_wait);
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Global Registers */
@@ -2664,7 +2664,7 @@ show_status(int line_num)
printk(" CyTBPR %x\n", base_addr[CyTBPR]);
printk(" CyTCOR %x\n", base_addr[CyTCOR]);
- restore_flags(flags);
+ local_irq_restore(flags);
} /* show_status */
#endif
@@ -2764,7 +2764,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
u_char do_lf = 0;
int i = 0;
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Ensure transmitter is enabled! */
@@ -2811,7 +2811,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
base_addr[CyIER] = ier;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static kdev_t serial167_console_device(struct console *c)
@@ -2855,7 +2855,7 @@ void putDebugChar (int c)
u_char ier;
int port;
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Ensure transmitter is enabled! */
@@ -2885,7 +2885,7 @@ void putDebugChar (int c)
base_addr[CyIER] = ier;
- restore_flags(flags);
+ local_irq_restore(flags);
}
int getDebugChar()
@@ -2907,7 +2907,7 @@ int getDebugChar()
}
/* OK, nothing in queue, wait in poll loop */
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Ensure receiver is enabled! */
@@ -2953,7 +2953,7 @@ int getDebugChar()
base_addr[CyIER] = ier;
- restore_flags(flags);
+ local_irq_restore(flags);
return (c);
}
@@ -2979,7 +2979,7 @@ debug_setup()
cflag = B19200;
- save_flags(flags); cli();
+ local_irq_save(flags);
for (i = 0; i < 4; i++)
{
@@ -3034,7 +3034,7 @@ debug_setup()
base_addr[CyIER] = CyRxData;
- restore_flags(flags);
+ local_irq_restore(flags);
} /* debug_setup */
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 5b0351cc11cf..4cadd82064be 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -624,11 +624,10 @@ static void scc_disable_tx_interrupts(void *ptr)
unsigned long flags;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
port->gs.flags &= ~GS_TX_INTEN;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -638,12 +637,11 @@ static void scc_enable_tx_interrupts(void *ptr)
unsigned long flags;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
/* restart the transmitter */
scc_tx_int (0, port, 0);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -653,11 +651,10 @@ static void scc_disable_rx_interrupts(void *ptr)
unsigned long flags;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(INT_AND_DMA_REG,
~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -667,11 +664,10 @@ static void scc_enable_rx_interrupts(void *ptr)
unsigned long flags;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(INT_AND_DMA_REG, 0xff,
IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -717,10 +713,9 @@ static int scc_set_real_termios (void *ptr)
if (baud == 0) {
/* speed == 0 -> drop DTR */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
@@ -748,8 +743,7 @@ static int scc_set_real_termios (void *ptr)
brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;
#endif
/* Now we have all parameters and can go to set them: */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* receiver's character size and auto-enables */
SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
@@ -773,7 +767,7 @@ static int scc_set_real_termios (void *ptr)
/* BRG enable, and clock source never changes */
SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -823,13 +817,12 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts)
unsigned char t;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
t = SCCread(TX_CTRL_REG);
if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
SCCwrite(TX_CTRL_REG, t);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -914,8 +907,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
};
#endif
if (!(port->gs.flags & ASYNC_INITIALIZED)) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i)
@@ -934,7 +926,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
port->c_dcd = 0; /* Prevent initial 1->0 interrupt */
scc_setsignals (port, 1,1);
- restore_flags(flags);
+ local_irq_restore(flags);
}
tty->driver_data = port;
@@ -982,10 +974,9 @@ static void scc_throttle (struct tty_struct * tty)
SCC_ACCESS_INIT(port);
if (tty->termios->c_cflag & CRTSCTS) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (I_IXOFF(tty))
scc_send_xchar(tty, STOP_CHAR(tty));
@@ -999,10 +990,9 @@ static void scc_unthrottle (struct tty_struct * tty)
SCC_ACCESS_INIT(port);
if (tty->termios->c_cflag & CRTSCTS) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (I_IXOFF(tty))
scc_send_xchar(tty, START_CHAR(tty));
@@ -1022,11 +1012,10 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state)
unsigned long flags;
SCC_ACCESS_INIT(port);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK,
break_state ? TCR_SEND_BREAK : 0);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1069,8 +1058,7 @@ static void scc_console_write (struct console *co, const char *str, unsigned cou
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
while (count--)
{
@@ -1078,7 +1066,7 @@ static void scc_console_write (struct console *co, const char *str, unsigned cou
scc_ch_write ('\r');
scc_ch_write (*str++);
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
static kdev_t scc_console_device(struct console *c)
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 89e956d8b011..64ee462aaa97 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -743,7 +743,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
ide_startstop_t startstop;
/* for atari only: POSSIBLY BROKEN HERE(?) */
- ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
+ ide_get_lock(ide_intr, hwgroup);
/* necessary paranoia: ensure IRQs are masked on local CPU */
local_irq_disable();
@@ -783,7 +783,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
*/
/* for atari only */
- ide_release_lock(&ide_intr_lock);
+ ide_release_lock();
hwgroup->busy = 0;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9b4130b92ae6..3c07fbefa9bf 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -181,14 +181,6 @@ spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
-#ifdef IDE_ARCH_LOCK
-/*
- * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-static int ide_intr_lock;
-#endif /* IDE_ARCH_LOCK */
-
#ifdef CONFIG_IDEDMA_AUTO
int noautodma = 0;
#else
@@ -2097,12 +2089,12 @@ void __init ide_init_builtin_drivers (void)
#ifdef CONFIG_BLK_DEV_IDE
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
+ ide_get_lock(NULL, NULL); /* for atari only */
(void) ideprobe_init();
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- ide_release_lock(&ide_intr_lock); /* for atari only */
+ ide_release_lock(); /* for atari only */
#endif /* CONFIG_BLK_DEV_IDE */
#ifdef CONFIG_PROC_FS
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 0ff0a3c54cff..f51ff785d0ab 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/amigahw.h>
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index d0a5b7617fd3..5e1cea29ffb2 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 91b9de9c5d47..f89593c4f4bf 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/setup.h>
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index c54b7317e59f..ad69eedf557e 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serio.h>
+#include <linux/interrupt.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
@@ -54,7 +55,6 @@ static int q40kbd_open(struct serio *port)
}
static void q40kbd_close(struct serio *port)
{
- return 0;
}
static struct serio q40kbd_port =
@@ -69,8 +69,6 @@ static struct serio q40kbd_port =
static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long flags;
-
if (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
if (q40kbd_port.dev)
q40kbd_port.dev->interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0);
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index cf0504e0e233..9a2392ac290e 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -83,15 +83,14 @@ static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
struct adb_request *req;
uint flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
req = current_req;
if ((adb_iop_state == sending) && req && req->reply_expected) {
adb_iop_state = awaiting_reply;
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -107,8 +106,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
struct adb_request *req;
uint flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
req = current_req;
@@ -150,7 +148,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
memcpy(msg->reply, msg->message, IOP_MSG_LEN);
}
iop_complete_message(msg);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -170,8 +168,7 @@ static void adb_iop_start(void)
req = current_req;
if (!req) return;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#ifdef DEBUG_ADB_IOP
printk("adb_iop_start: sending packet, %d bytes:", req->nbytes);
@@ -192,7 +189,7 @@ static void adb_iop_start(void)
req->sent = 1;
adb_iop_state = sending;
- restore_flags(flags);
+ local_irq_restore(flags);
/* Now send it. The IOP manager will call adb_iop_complete */
/* when the packet has been sent. */
@@ -236,8 +233,7 @@ static int adb_iop_write(struct adb_request *req)
return -EINVAL;
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
req->next = 0;
req->sent = 0;
@@ -252,7 +248,7 @@ static int adb_iop_write(struct adb_request *req)
last_req = req;
}
- restore_flags(flags);
+ local_irq_restore(flags);
if (adb_iop_state == idle) adb_iop_start();
return 0;
}
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 38b2c1afdaba..32dcc992231e 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -18,6 +18,7 @@
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#ifdef CONFIG_PPC
#include <asm/prom.h>
#include <asm/machdep.h>
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 82cc3df633f1..0aa34eebe478 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/adb.h>
+#include <linux/interrupt.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/machw.h>
@@ -144,8 +145,7 @@ int macii_init(void)
unsigned long flags;
int err;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
err = macii_init_via();
if (err) return err;
@@ -155,7 +155,7 @@ int macii_init(void)
if (err) return err;
macii_state = idle;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -196,13 +196,12 @@ static void macii_queue_poll(void)
adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
ADB_READREG(device, 0));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
req.next = current_req;
current_req = &req;
- restore_flags(flags);
+ local_irq_restore(flags);
macii_start();
in_poll--;
}
@@ -221,8 +220,7 @@ static void macii_retransmit(int device)
adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
ADB_READREG(device, 0));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (current_req != NULL) {
last_req->next = &rt;
@@ -234,7 +232,7 @@ static void macii_retransmit(int device)
if (macii_state == idle) macii_start();
- restore_flags(flags);
+ local_irq_restore(flags);
in_retransmit--;
}
@@ -267,7 +265,7 @@ static int macii_write(struct adb_request *req)
req->complete = 0;
req->reply_len = 0;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (current_req != NULL) {
last_req->next = req;
@@ -278,7 +276,7 @@ static int macii_write(struct adb_request *req)
if (macii_state == idle) macii_start();
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -296,9 +294,9 @@ static void macii_poll(void)
{
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Reset the bus */
@@ -328,7 +326,7 @@ static void macii_start(void)
return;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
/*
* IRQ signaled ?? (means ADB controller wants to send, or might
@@ -356,7 +354,7 @@ static void macii_start(void)
(uint) via[B] & (ST_MASK|TREQ));
retry_req = req;
/* set ADB status here ? */
- restore_flags(flags);
+ local_irq_restore(flags);
return;
} else {
need_poll = 0;
@@ -385,7 +383,7 @@ static void macii_start(void)
macii_state = sending;
data_index = 2;
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -421,10 +419,10 @@ void macii_interrupt(int irq, void *arg, struct pt_regs *regs)
last_status = status;
/* prevent races due to SCSI enabling ints */
- save_flags(flags); cli();
+ local_irq_save(flags);
if (driver_running) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -650,5 +648,5 @@ void macii_interrupt(int irq, void *arg, struct pt_regs *regs)
}
/* reset mutex and interrupts */
driver_running = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
index 7a32a295fd52..162ce3f2acd0 100644
--- a/drivers/macintosh/via-maciisi.c
+++ b/drivers/macintosh/via-maciisi.c
@@ -22,6 +22,7 @@
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/machw.h>
@@ -312,8 +313,7 @@ maciisi_write(struct adb_request* req)
req->complete = 0;
req->reply_len = 0;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (current_req) {
last_req->next = req;
@@ -327,7 +327,7 @@ maciisi_write(struct adb_request* req)
i = maciisi_start();
if(i != 0)
{
- restore_flags(flags);
+ local_irq_restore(flags);
return i;
}
}
@@ -336,11 +336,11 @@ maciisi_write(struct adb_request* req)
#ifdef DEBUG_MACIISI_ADB
printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
return -EBUSY;
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -401,15 +401,14 @@ maciisi_poll(void)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (via[IFR] & SR_INT) {
maciisi_interrupt(0, 0, 0);
}
else /* avoid calling this function too quickly in a loop */
udelay(ADB_DELAY);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Shift register interrupt - this is *supposed* to mean that the
@@ -426,8 +425,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
status = via[B] & (TIP|TREQ);
#ifdef DEBUG_MACIISI_ADB
@@ -437,7 +435,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
if (!(via[IFR] & SR_INT)) {
/* Shouldn't happen, we hope */
printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n");
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -636,7 +634,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
default:
printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index 50f62a8d2505..3bb653489391 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/adb.h>
#include <linux/pmu.h>
@@ -495,7 +496,7 @@ pmu_queue_request(struct adb_request *req)
req->next = 0;
req->sent = 0;
req->complete = 0;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (current_req != 0) {
last_req->next = req;
@@ -507,7 +508,7 @@ pmu_queue_request(struct adb_request *req)
pmu_start();
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -537,7 +538,7 @@ pmu_start()
/* assert pmu_state == idle */
/* get the packet to send */
- save_flags(flags); cli();
+ local_irq_save(flags);
req = current_req;
if (req == 0 || pmu_state != idle
|| (req->reply_expected && req_awaiting_reply))
@@ -551,16 +552,15 @@ pmu_start()
send_byte(req->data[0]);
out:
- restore_flags(flags);
+ local_irq_restore(flags);
}
void
pmu_poll()
{
- unsigned long cpu_flags;
+ unsigned long flags;
- save_flags(cpu_flags);
- cli();
+ local_irq_save(flags);
if (via1[IFR] & SR_INT) {
via1[IFR] = SR_INT;
pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);
@@ -569,7 +569,7 @@ pmu_poll()
via1[IFR] = CB1_INT;
pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);
}
- restore_flags(cpu_flags);
+ local_irq_restore(flags);
}
static void
@@ -963,9 +963,9 @@ int __openfirmware powerbook_sleep(void)
asm volatile("mfspr %0,1008" : "=r" (hid0) :);
hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
asm volatile("mtspr 1008,%0" : : "r" (hid0));
- save_flags(msr);
+ local_save_flags(msr);
msr |= MSR_POW | MSR_EE;
- restore_flags(msr);
+ local_irq_restore(msr);
udelay(10);
/* OK, we're awake again, start restoring things */
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 7661224c7286..9c986c98384b 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -571,11 +571,10 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
skblen = skb->len;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!TX_BUFFS_AVAIL){
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
@@ -616,7 +615,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- restore_flags(flags);
+ local_irq_restore(flags);
return status;
}
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 9055f2a8317b..ea8272358c98 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -604,8 +604,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
entry = priv->cur_tx % TX_RING_SIZE;
@@ -662,7 +661,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
priv->tx_full = 1;
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -765,13 +764,12 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev)
short saved_addr;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
saved_addr = lance->RAP;
lance->RAP = CSR112; /* Missed Frame Count */
priv->stats.rx_missed_errors = swapw(lance->RDP);
lance->RAP = saved_addr;
- restore_flags(flags);
+ local_irq_restore(flags);
return &priv->stats;
}
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 4dd5791c553c..1cd15dae2a5b 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -235,8 +235,7 @@ get_frame(unsigned long paddr, int odd) {
unsigned long flags;
DISABLE_IRQ();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
dma_wd.dma_mode_status = 0x9a;
dma_wd.dma_mode_status = 0x19a;
@@ -247,7 +246,7 @@ get_frame(unsigned long paddr, int odd) {
dma_wd.dma_md = (unsigned char)paddr;
paddr >>= 8;
dma_wd.dma_hi = (unsigned char)paddr;
- restore_flags(flags);
+ local_irq_restore(flags);
c = sendcmd(0,0x00,NODE_ADR | C_READ); /* CMD: READ */
if( c < 128 ) goto rend;
@@ -284,8 +283,7 @@ hardware_send_packet(unsigned long paddr, int cnt) {
unsigned long flags;
DISABLE_IRQ();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
dma_wd.dma_mode_status = 0x19a;
dma_wd.dma_mode_status = 0x9a;
@@ -297,7 +295,7 @@ hardware_send_packet(unsigned long paddr, int cnt) {
dma_wd.dma_hi = (unsigned char)paddr;
dma_wd.fdc_acces_seccount = 0x4; /* sector count */
- restore_flags(flags);
+ local_irq_restore(flags);
c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */
c = sendcmd(1,0x100,cnt&0xff);
@@ -438,11 +436,10 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
/* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (stdma_islocked()) {
- restore_flags(flags);
+ local_irq_restore(flags);
lp->stats.tx_errors++;
}
else {
@@ -451,7 +448,7 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
int stat;
stdma_lock(bionet_intr, NULL);
- restore_flags(flags);
+ local_irq_restore(flags);
if( !STRAM_ADDR(buf+length-1) ) {
memcpy(nic_packet->buffer, skb->data, length);
buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
@@ -504,20 +501,19 @@ bionet_poll_rx(struct net_device *dev) {
int pkt_len, status;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* ++roman: Take care at locking the ST-DMA... This must be done with ints
* off, since otherwise an int could slip in between the question and the
* locking itself, and then we'd go to sleep... And locking itself is
* necessary to keep the floppy_change timer from working with ST-DMA
* registers. */
if (stdma_islocked()) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
stdma_lock(bionet_intr, NULL);
DISABLE_IRQ();
- restore_flags(flags);
+ local_irq_restore(flags);
if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index c42659667d35..95d6640fabd5 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -702,11 +702,10 @@ pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) {
/* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (stdma_islocked()) {
- restore_flags(flags);
+ local_irq_restore(flags);
lp->stats.tx_errors++;
}
else {
@@ -717,7 +716,7 @@ pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) {
stdma_lock(pamsnet_intr, NULL);
DISABLE_IRQ();
- restore_flags(flags);
+ local_irq_restore(flags);
if( !STRAM_ADDR(buf+length-1) ) {
memcpy(nic_packet->buffer, skb->data, length);
buf = (unsigned long)phys_nic_packet;
@@ -749,20 +748,19 @@ pamsnet_poll_rx(struct net_device *dev) {
struct sk_buff *skb;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* ++roman: Take care at locking the ST-DMA... This must be done with ints
* off, since otherwise an int could slip in between the question and the
* locking itself, and then we'd go to sleep... And locking itself is
* necessary to keep the floppy_change timer from working with ST-DMA
* registers. */
if (stdma_islocked()) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
stdma_lock(pamsnet_intr, NULL);
DISABLE_IRQ();
- restore_flags(flags);
+ local_irq_restore(flags);
boguscount = testpkt(lance_target);
if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index e8e91d299896..a23c024c1da1 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -402,8 +402,7 @@ static int __init addr_accessible( volatile void *regp, int wordflag, int writef
long flags;
long *vbr, save_berr;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
__asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : );
save_berr = vbr[2];
@@ -440,7 +439,7 @@ static int __init addr_accessible( volatile void *regp, int wordflag, int writef
);
vbr[2] = save_berr;
- restore_flags(flags);
+ local_irq_restore(flags);
return( ret );
}
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index c6255c3b8f21..45c74135572f 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -194,7 +194,7 @@ int __init mac8390_memsize(unsigned long membase)
unsigned long flags;
int i, j;
- save_flags(flags); cli();
+ local_irq_save(flags);
/* Check up to 32K in 4K increments */
for (i = 0; i < 8; i++) {
volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000));
@@ -217,7 +217,7 @@ int __init mac8390_memsize(unsigned long membase)
break;
}
}
- restore_flags(flags);
+ local_irq_restore(flags);
/* in any case, we stopped once we tried one block too many,
or once we reached 32K */
return i * 0x1000;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index ba9adba053a0..95f72759aa0f 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -52,7 +52,8 @@
Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
check kmalloc and release the allocated memory on failure in
mac89x0_probe and in init_module
- use save_flags/restore_flags in net_get_stat, not just cli/sti
+ use local_irq_{save,restore}(flags) in net_get_stat, not just
+ local_irq_{dis,en}able()
*/
static char *version =
@@ -199,11 +200,10 @@ int __init mac89x0_probe(struct net_device *dev)
unsigned long flags;
int card_present;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
card_present = hwreg_present((void*) ioaddr+4)
&& hwreg_present((void*) ioaddr + DATA_PORT);
- restore_flags(flags);
+ local_irq_restore(flags);
if (!card_present)
return -ENODEV;
@@ -397,8 +397,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* keep the upload from being interrupted, since we
ask the chip to start transmitting before the
whole packet has been completely uploaded. */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* initiate a transmit sequence */
writereg(dev, PP_TxCMD, lp->send_cmd);
@@ -408,14 +407,14 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
/* Gasp! It hasn't. But that shouldn't happen since
we're waiting for TxOk, so return 1 and requeue this packet. */
- restore_flags(flags);
+ local_irq_restore(flags);
return 1;
}
/* Write the contents of the packet */
memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
- restore_flags(flags);
+ local_irq_restore(flags);
dev->trans_start = jiffies;
}
dev_kfree_skb (skb);
@@ -568,12 +567,11 @@ net_get_stats(struct net_device *dev)
struct net_local *lp = (struct net_local *)dev->priv;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Update the statistics from the device registers. */
lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
- restore_flags(flags);
+ local_irq_restore(flags);
return &lp->stats;
}
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 7bab986b43b4..4e8a08b78804 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -256,8 +256,7 @@ static int mace_set_address(struct net_device *dev, void *addr)
unsigned long flags;
u8 maccc;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
maccc = mb->maccc;
@@ -270,7 +269,7 @@ static int mace_set_address(struct net_device *dev, void *addr)
}
mb->maccc = maccc;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index e87f5aad0542..16c7160e0eb0 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -332,10 +332,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
unsigned long flags;
int card_present;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS);
- restore_flags(flags);
+ local_irq_restore(flags);
if (!card_present) {
printk("none.\n");
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index cdd2252d83cf..61b6e3be8557 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -1078,12 +1078,11 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if(p->xmit_count != p->xmit_last)
netif_wake_queue(dev);
p->lock = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
dev_kfree_skb(skb);
#endif
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index ed2070e280f0..70dbe64a2612 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -574,7 +574,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
#endif
/* We're not prepared for the int until the last flags are set/reset.
* And the int may happen already after setting the OWN_CHIP... */
- save_and_cli(flags);
+ local_irq_save(flags);
/* Mask to ring buffer boundary. */
entry = lp->new_tx;
@@ -610,7 +610,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
TMD1_OWN_HOST)
netif_start_queue(dev);
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index d6cfff7ff8fa..14cbe34eb897 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -915,10 +915,9 @@ void __init nubus_probe_slot(int slot)
int card_present;
rp--;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
card_present = hwreg_present(rp);
- restore_flags(flags);
+ local_irq_restore(flags);
if (!card_present)
continue;
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index b09e1f2d5441..d1caad0d6744 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/ioport.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index ae831176b7b1..461b3ffa2a66 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/parport.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
#include <asm/irq.h>
@@ -25,11 +26,10 @@ parport_atari_read_data(struct parport *p)
unsigned long flags;
unsigned char data;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 15;
data = sound_ym.rd_data_reg_sel;
- restore_flags(flags);
+ local_irq_restore(flags);
return data;
}
@@ -38,11 +38,10 @@ parport_atari_write_data(struct parport *p, unsigned char data)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 15;
sound_ym.wd_data = data;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static unsigned char
@@ -51,12 +50,11 @@ parport_atari_read_control(struct parport *p)
unsigned long flags;
unsigned char control = 0;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 14;
if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
control = PARPORT_CONTROL_STROBE;
- restore_flags(flags);
+ local_irq_restore(flags);
return control;
}
@@ -65,14 +63,13 @@ parport_atari_write_control(struct parport *p, unsigned char control)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
sound_ym.rd_data_reg_sel = 14;
if (control & PARPORT_CONTROL_STROBE)
sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
else
sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
- restore_flags(flags);
+ local_irq_restore(flags);
}
static unsigned char
@@ -129,12 +126,11 @@ parport_atari_data_forward(struct parport *p)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Soundchip port B as output. */
sound_ym.rd_data_reg_sel = 7;
sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x40;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void
@@ -143,12 +139,11 @@ parport_atari_data_reverse(struct parport *p)
#if 0 /* too dangerous, can kill sound chip */
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Soundchip port B as input. */
sound_ym.rd_data_reg_sel = 7;
sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40;
- restore_flags(flags);
+ local_irq_restore(flags);
#endif
}
@@ -209,15 +204,14 @@ parport_atari_init(void)
unsigned long flags;
if (MACH_IS_ATARI) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Soundchip port A/B as output. */
sound_ym.rd_data_reg_sel = 7;
sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
/* STROBE high. */
sound_ym.rd_data_reg_sel = 14;
sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
- restore_flags(flags);
+ local_irq_restore(flags);
/* MFP port I0 as input. */
mfp.data_dir &= ~1;
/* MFP port I0 interrupt on high->low edge. */
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 2f78ad1450d8..e6582994fb99 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -59,6 +59,7 @@
#include <linux/delay.h>
#include <linux/mc6821.h>
#include <linux/zorro.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index e05fb57bda60..f30641c4a23c 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -593,6 +593,7 @@ static void yenta_open_bh(void * data)
if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
+ init_timer(&socket->poll_timer);
socket->poll_timer.function = yenta_interrupt_wrapper;
socket->poll_timer.data = (unsigned long)socket;
socket->poll_timer.expires = jiffies + HZ;
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 4715fc295c29..e9b395952b38 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -251,6 +251,7 @@
#include <linux/time.h>
#include <linux/blk.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <asm/pgtable.h>
#ifdef CONFIG_AMIGA
@@ -713,15 +714,14 @@ request_synchronous (int host, int target) {
}
hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (hostdata->initiate_sdtr & (1 << target)) {
- restore_flags(flags);
+ local_irq_restore(flags);
printk (KERN_ALERT "target %d already doing SDTR\n", target);
return -1;
}
hostdata->initiate_sdtr |= (1 << target);
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
#endif
@@ -1588,11 +1588,10 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
/* The NCR chip _must_ be idle to run the test scripts */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!hostdata->idle) {
printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
@@ -1616,7 +1615,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
DCNTL_STD);
printk (" started\n");
- restore_flags(flags);
+ local_irq_restore(flags);
/*
* This is currently a .5 second timeout, since (in theory) no slow
@@ -1655,7 +1654,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
hostdata->script, start);
printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
NCR53c7x0_read32(DSPS_REG));
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
hostdata->test_running = 0;
@@ -1690,10 +1689,10 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
if (!hostdata->valid_ids[i])
continue;
#endif
- cli();
+ local_irq_disable();
if (!hostdata->idle) {
printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
@@ -1709,7 +1708,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
if (hostdata->options & OPTION_DEBUG_TRACE)
NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
DCNTL_SSM | DCNTL_STD);
- restore_flags(flags);
+ local_irq_restore(flags);
timeout = jiffies + 5 * HZ; /* arbitrary */
while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
@@ -1731,19 +1730,19 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
host->host_no, i);
if (!hostdata->idle) {
printk("scsi%d : not idle\n", host->host_no);
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
} else if (hostdata->test_completed == -1) {
printk ("scsi%d : test 2 timed out\n", host->host_no);
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
hostdata->test_running = 0;
}
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -1826,8 +1825,7 @@ static volatile int process_issue_queue_running = 0;
static __inline__ void
run_process_issue_queue(void) {
unsigned long flags;
- save_flags (flags);
- cli();
+ local_irq_save(flags);
if (!process_issue_queue_running) {
process_issue_queue_running = 1;
process_issue_queue(flags);
@@ -1837,7 +1835,7 @@ run_process_issue_queue(void) {
* interrupts disabled.
*/
}
- restore_flags (flags);
+ local_irq_restore(flags);
}
/*
@@ -1871,8 +1869,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
printk ("scsi%d: abnormal finished\n", host->host_no);
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
found = 0;
/*
* Traverse the NCR issue array until we find a match or run out
@@ -1955,7 +1952,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
c->result = result;
c->scsi_done(c);
- restore_flags(flags);
+ local_irq_restore(flags);
run_process_issue_queue();
}
@@ -1990,8 +1987,7 @@ intr_break (struct Scsi_Host *host, struct
* dump the appropriate debugging information to standard
* output.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
for (bp = hostdata->breakpoints; bp && bp->address != dsp;
bp = bp->next);
@@ -2013,7 +2009,7 @@ intr_break (struct Scsi_Host *host, struct
* instruction in bytes.
*/
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
* Function : static void print_synchronous (const char *prefix,
@@ -2919,8 +2915,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) {
host->hostdata[0];
NCR53c7x0_local_setup(host);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Disable scsi chip and s/w level 7 ints */
@@ -3021,7 +3016,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) {
}
#endif
/* Anything needed for your hardware? */
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -3122,19 +3117,17 @@ allocate_cmd (Scsi_Cmnd *cmd) {
tmp->real = (void *)real;
tmp->size = size;
tmp->free = ((void (*)(void *, int)) my_free_page);
- save_flags (flags);
- cli();
+ local_irq_save(flags);
tmp->next = hostdata->free;
hostdata->free = tmp;
- restore_flags (flags);
+ local_irq_restore(flags);
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
tmp = (struct NCR53c7x0_cmd *) hostdata->free;
if (tmp) {
hostdata->free = tmp->next;
}
- restore_flags(flags);
+ local_irq_restore(flags);
if (!tmp)
printk ("scsi%d : can't allocate command for target %d lun %d\n",
host->host_no, cmd->target, cmd->lun);
@@ -3353,19 +3346,17 @@ create_cmd (Scsi_Cmnd *cmd) {
memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
sizeof(wdtr_message));
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->initiate_wdtr &= ~(1 << cmd->target);
- restore_flags(flags);
+ local_irq_restore(flags);
} else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
sizeof(sdtr_message));
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
tmp->flags |= CMD_FLAG_SDTR;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->initiate_sdtr &= ~(1 << cmd->target);
- restore_flags(flags);
+ local_irq_restore(flags);
}
#if 1
@@ -3622,8 +3613,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
}
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
|| ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
!(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun)))
@@ -3638,7 +3628,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
cmd->target, cmd->lun);
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
- restore_flags (flags);
+ local_irq_restore(flags);
return 0;
}
@@ -3647,7 +3637,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
printk("scsi%d : maximum commands exceeded\n", host->host_no);
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
- restore_flags (flags);
+ local_irq_restore(flags);
return 0;
}
@@ -3659,7 +3649,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
host->host_no);
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
- restore_flags (flags);
+ local_irq_restore(flags);
return 0;
}
}
@@ -3686,7 +3676,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
tmp->SCp.ptr = (unsigned char *) cmd;
}
- restore_flags (flags);
+ local_irq_restore(flags);
run_process_issue_queue();
return 0;
}
@@ -3726,8 +3716,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
virt_to_bus(hostdata->dsa), hostdata->dsa);
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/*
* Work around race condition : if an interrupt fired and we
@@ -3740,7 +3729,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
- restore_flags (flags);
+ local_irq_restore(flags);
return;
}
@@ -3770,7 +3759,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
- restore_flags (flags);
+ local_irq_restore(flags);
return;
}
@@ -3791,7 +3780,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -3849,12 +3838,12 @@ process_issue_queue (unsigned long flags) {
*/
do {
- cli(); /* Freeze request queues */
+ local_irq_disable(); /* Freeze request queues */
done = 1;
for (host = first_host; host && host->hostt == the_template;
host = host->next) {
hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- cli();
+ local_irq_disable();
if (hostdata->issue_queue) {
if (hostdata->state == STATE_DISABLED) {
tmp = (Scsi_Cmnd *) hostdata->issue_queue;
@@ -3904,7 +3893,7 @@ process_issue_queue (unsigned long flags) {
} /* if target/lun is not busy */
} /* if hostdata->issue_queue */
if (!done)
- restore_flags (flags);
+ local_irq_restore(flags);
} /* for host */
} while (!done);
process_issue_queue_running = 0;
@@ -4171,8 +4160,7 @@ NCR53c7x0_intfly (struct Scsi_Host *host)
* completion.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
restart:
for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list),
cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
@@ -4226,7 +4214,7 @@ restart:
tmp->scsi_done(tmp);
goto restart;
}
- restore_flags(flags);
+ local_irq_restore(flags);
if (!search_found) {
printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
@@ -4906,13 +4894,12 @@ intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
/* Don't print instr. until we write DSP at end of intr function */
} else if (hostdata->options & OPTION_DEBUG_SINGLE) {
print_insn (host, dsp, "s ", 0);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* XXX - should we do this, or can we get away with writing dsp? */
NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
~DCNTL_SSM) | DCNTL_STD);
- restore_flags(flags);
+ local_irq_restore(flags);
} else {
printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
" ", host->host_no);
@@ -5190,8 +5177,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
return SCSI_ABORT_BUSY;
}
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#if 0
if (cache_pid == cmd->pid)
panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
@@ -5226,7 +5212,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
cmd->scsi_done(cmd);
printk ("scsi%d : found command %ld in Linux issue queue\n",
host->host_no, me->pid);
- restore_flags(flags);
+ local_irq_restore(flags);
run_process_issue_queue();
return SCSI_ABORT_SUCCESS;
}
@@ -5252,12 +5238,12 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
cmd->scsi_done(cmd);
printk ("scsi%d : found finished command %ld in running list\n",
host->host_no, cmd->pid);
- restore_flags(flags);
+ local_irq_restore(flags);
return SCSI_ABORT_NOT_RUNNING;
} else {
printk ("scsi%d : DANGER : command running, can not abort.\n",
cmd->host->host_no);
- restore_flags(flags);
+ local_irq_restore(flags);
return SCSI_ABORT_BUSY;
}
}
@@ -5289,7 +5275,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
*/
--hostdata->busy[cmd->target][cmd->lun];
}
- restore_flags(flags);
+ local_irq_restore(flags);
cmd->scsi_done(cmd);
/*
@@ -5337,8 +5323,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
(struct NCR53c7x0_hostdata *) host->hostdata[0];
NCR53c7x0_local_setup(host);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
ncr_halt (host);
print_lots (host);
dump_events (host, 30);
@@ -5372,13 +5357,13 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
disable(host);
else if (hostdata->resets != -1)
--hostdata->resets;
- restore_flags(flags);
+ local_irq_restore(flags);
for (; nuke_list; nuke_list = tmp) {
tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
nuke_list->result = DID_RESET << 16;
nuke_list->scsi_done (nuke_list);
}
- restore_flags(flags);
+ local_irq_restore(flags);
return SCSI_RESET_SUCCESS;
}
@@ -5607,8 +5592,7 @@ print_queues (struct Scsi_Host *host) {
left >= 0 && cmd;
cmd = next_cmd) {
next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (cmd->host_scribble) {
if (check_address ((unsigned long) (cmd->host_scribble),
sizeof (cmd->host_scribble)) == -1)
@@ -5621,7 +5605,7 @@ print_queues (struct Scsi_Host *host) {
} else
printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
host->host_no, cmd->pid, cmd->target, cmd->lun);
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (left <= 0) {
@@ -5653,8 +5637,7 @@ print_queues (struct Scsi_Host *host) {
dsa = bus_to_virt (hostdata->reconnect_dsa_head);
left >= 0 && dsa;
dsa = next_dsa) {
- save_flags (flags);
- cli();
+ local_irq_save(flags);
if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
dsa);
@@ -5665,7 +5648,7 @@ print_queues (struct Scsi_Host *host) {
next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
print_dsa (host, dsa, "");
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
if (left < 0)
@@ -5755,15 +5738,14 @@ shutdown (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata[0];
NCR53c7x0_local_setup(host);
- save_flags (flags);
- cli();
+ local_irq_save(flags);
/* Get in a state where we can reset the SCSI bus */
ncr_halt (host);
ncr_scsi_reset (host);
hostdata->soft_reset(host);
disable (host);
- restore_flags (flags);
+ local_irq_restore(flags);
return 0;
}
@@ -5778,12 +5760,11 @@ ncr_scsi_reset (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
unsigned long flags;
NCR53c7x0_local_setup(host);
- save_flags (flags);
- cli();
+ local_irq_save(flags);
NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
udelay(25); /* Minimum amount of time to assert RST */
NCR53c7x0_write8(SCNTL1_REG, 0);
- restore_flags (flags);
+ local_irq_restore(flags);
}
/*
@@ -5796,13 +5777,12 @@ hard_reset (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata[0];
unsigned long flags;
- save_flags (flags);
- cli();
+ local_irq_save(flags);
ncr_scsi_reset(host);
NCR53c7x0_driver_init (host);
if (hostdata->soft_reset)
hostdata->soft_reset (host);
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -5898,14 +5878,13 @@ disable (struct Scsi_Host *host) {
host->hostdata[0];
unsigned long flags;
Scsi_Cmnd *nuke_list, *tmp;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (hostdata->state != STATE_HALTED)
ncr_halt (host);
nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
hard_reset (host);
hostdata->state = STATE_DISABLED;
- restore_flags(flags);
+ local_irq_restore(flags);
printk ("scsi%d : nuking commands\n", host->host_no);
for (; nuke_list; nuke_list = tmp) {
tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
@@ -5938,8 +5917,7 @@ ncr_halt (struct Scsi_Host *host) {
int stage;
NCR53c7x0_local_setup(host);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Stage 0 : eat all interrupts
Stage 1 : set ABORT
Stage 2 : eat all but abort interrupts
@@ -5974,7 +5952,7 @@ ncr_halt (struct Scsi_Host *host) {
}
}
hostdata->state = STATE_HALTED;
- restore_flags(flags);
+ local_irq_restore(flags);
#if 0
print_lots (host);
#endif
@@ -6022,14 +6000,13 @@ dump_events (struct Scsi_Host *host, int count) {
count = hostdata->event_size;
for (i = hostdata->event_index; count > 0;
i = (i ? i - 1 : hostdata->event_size -1), --count) {
- save_flags(flags);
/*
* By copying the event we're currently examining with interrupts
* disabled, we can do multiple printk(), etc. operations and
* still be guaranteed that they're happening on the same
* event structure.
*/
- cli();
+ local_irq_save(flags);
#if 0
event = hostdata->events[i];
#else
@@ -6037,7 +6014,7 @@ dump_events (struct Scsi_Host *host, int count) {
sizeof(event));
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
host->host_no, event_name (event.event), count,
(long) event.time.tv_sec, (long) event.time.tv_usec,
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index cb389fef9700..4499f1f6b3ae 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -2489,8 +2489,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no));
- } else {
+ } else
#endif /* def AUTOSENSE */
+ {
collect_stats(hostdata, cmd);
cmd->scsi_done(cmd);
}
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index ead703c05e88..43681be4afd5 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -715,6 +715,9 @@ void esp_initialize(struct NCR_ESP *esp)
esp->targets_present = 0;
esp->resetting_bus = 0;
esp->snip = 0;
+
+ init_waitqueue_head(&esp->reset_queue);
+
esp->fas_premature_intr_workaround = 0;
for(i = 0; i < 32; i++)
esp->espcmdlog[i] = 0;
@@ -1037,25 +1040,6 @@ static void esp_exec_cmd(struct NCR_ESP *esp)
lun = SCptr->lun;
target = SCptr->target;
- /*
- * If esp_dev == NULL then we need to allocate a struct for our data
- */
- if (!esp_dev) {
- esp_dev = kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
- if (!esp_dev) {
- /* We're SOL. Print a message and bail */
- printk(KERN_WARNING "esp: no mem for esp_device %d/%d\n",
- target, lun);
- esp->current_SC = NULL;
- SCptr->result = DID_ERROR << 16;
- SCptr->done(SCptr);
- return;
- }
- memset(esp_dev, 0, sizeof(struct esp_device));
- SDptr->hostdata = esp_dev;
- }
-
-
esp->snip = 0;
esp->msgout_len = 0;
@@ -1371,7 +1355,7 @@ static void esp_dump_state(struct NCR_ESP *esp,
ESPLOG(("\n"));
}
-/* Abort a command. */
+/* Abort a command. The host_lock is acquired by caller. */
int esp_abort(Scsi_Cmnd *SCptr)
{
struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
@@ -1392,7 +1376,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
esp->msgout_len = 1;
esp->msgout_ctr = 0;
esp_cmd(esp, eregs, ESP_CMD_SATN);
- return SCSI_ABORT_PENDING;
+ return SUCCESS;
}
/* If it is still in the issue queue then we can safely
@@ -1417,7 +1401,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
this->done(this);
if(don)
esp->dma_ints_on(esp);
- return SCSI_ABORT_SUCCESS;
+ return SUCCESS;
}
}
}
@@ -1430,19 +1414,19 @@ int esp_abort(Scsi_Cmnd *SCptr)
if(esp->current_SC) {
if(don)
esp->dma_ints_on(esp);
- return SCSI_ABORT_BUSY;
+ return FAILED;
}
/* It's disconnected, we have to reconnect to re-establish
* the nexus and tell the device to abort. However, we really
- * cannot 'reconnect' per se, therefore we tell the upper layer
- * the safest thing we can. This is, wait a bit, if nothing
- * happens, we are really hung so reset the bus.
+ * cannot 'reconnect' per se. Don't try to be fancy, just
+ * indicate failure, which causes our caller to reset the whole
+ * bus.
*/
if(don)
esp->dma_ints_on(esp);
- return SCSI_ABORT_SNOOZE;
+ return FAILED;
}
/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
@@ -1476,6 +1460,7 @@ static int esp_finish_reset(struct NCR_ESP *esp,
/* SCSI bus reset is complete. */
esp->resetting_bus = 0;
+ wake_up(&esp->reset_queue);
/* Ok, now it is safe to get commands going once more. */
if(esp->issue_SC)
@@ -1496,13 +1481,22 @@ static int esp_do_resetbus(struct NCR_ESP *esp,
/* Reset ESP chip, reset hanging bus, then kill active and
* disconnected commands for targets without soft reset.
+ *
+ * The host_lock is acquired by caller.
*/
-int esp_reset(Scsi_Cmnd *SCptr, unsigned int how)
+int esp_reset(Scsi_Cmnd *SCptr)
{
struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
(void) esp_do_resetbus(esp, esp->eregs);
- return SCSI_RESET_PENDING;
+
+ spin_unlock_irq(esp->ehost->host_lock);
+
+ wait_event(esp->reset_queue, (esp->resetting_bus == 0));
+
+ spin_lock_irq(esp->ehost->host_lock);
+
+ return SUCCESS;
}
/* Internal ESP done function. */
@@ -1859,8 +1853,7 @@ static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
ESPDATA(( /*"\n"*/ "\r"));
#endif
#if 0
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#endif
if(thisphase == in_datain) {
/* 'go' ... */
@@ -1951,7 +1944,7 @@ static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
ESPDATA(("done! \n"));
#if 0
- restore_flags(flags);
+ local_irq_restore(flags);
#endif
/* check new bus phase */
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index d8e161840e1a..3f20b6aaffa9 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -407,6 +407,7 @@ struct NCR_ESP {
* cannot be assosciated with any specific command.
*/
unchar resetting_bus;
+ wait_queue_head_t reset_queue;
unchar do_pio_cmds; /* Do command transfer with pio */
@@ -657,4 +658,11 @@ extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
extern void esp_intr(int, void *, struct pt_regs *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_command(Scsi_Cmnd *);
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *);
+extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout);
#endif /* !(NCR53C9X_H) */
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index d1f7b9fa0410..f8b04da74c83 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -230,7 +231,21 @@ int __init a2091_detect(Scsi_Host_Template *tpnt)
#define HOSTS_C
-static Scsi_Host_Template driver_template = A2091_SCSI;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "A2901",
+ .name = "Commodore A2091/A590 SCSI",
+ .detect = a2091_detect,
+ .release = a2091_release,
+ .queuecommand = wd33c93_queuecommand,
+ .abort = wd33c93_abort,
+ .reset = wd33c93_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
index ad0e524f65f3..3b6e57c742a3 100644
--- a/drivers/scsi/a2091.h
+++ b/drivers/scsi/a2091.h
@@ -30,19 +30,6 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#define CAN_QUEUE 16
#endif
-#define A2091_SCSI { .proc_name = "A2901", \
- .name = "Commodore A2091/A590 SCSI", \
- .detect = a2091_detect, \
- .release = a2091_release, \
- .queuecommand = wd33c93_queuecommand, \
- .abort = wd33c93_abort, \
- .reset = wd33c93_reset, \
- .can_queue = CAN_QUEUE, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = CMD_PER_LUN, \
- .use_clustering = DISABLE_CLUSTERING }
-
/*
* if the transfer address ANDed with this results in a non-zero
* result, then we can't use DMA.
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 15dd86e4b194..28a393b68c5c 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -6,6 +6,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -206,7 +207,21 @@ fail_register:
#define HOSTS_C
-static Scsi_Host_Template driver_template = _A3000_SCSI;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "A3000",
+ .name = "Amiga 3000 built-in SCSI",
+ .detect = a3000_detect,
+ .release = a3000_release,
+ .queuecommand = wd33c93_queuecommand,
+ .abort = wd33c93_abort,
+ .reset = wd33c93_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
index ee134f111792..ddd13e856fc4 100644
--- a/drivers/scsi/a3000.h
+++ b/drivers/scsi/a3000.h
@@ -30,20 +30,6 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#define CAN_QUEUE 16
#endif
-#define _A3000_SCSI { .proc_name = "A3000", \
- .proc_info = NULL, \
- .name = "Amiga 3000 built-in SCSI", \
- .detect = a3000_detect, \
- .release = a3000_release, \
- .queuecommand = wd33c93_queuecommand, \
- .abort = wd33c93_abort, \
- .reset = wd33c93_reset, \
- .can_queue = CAN_QUEUE, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = CMD_PER_LUN, \
- .use_clustering = ENABLE_CLUSTERING }
-
/*
* if the transfer address ANDed with this results in a non-zero
* result, then we can't use DMA.
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index c2404c8433f4..0b6c04b23581 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -87,7 +87,7 @@ config AIC79XX_DEBUG_MASK
config AIC79XX_REG_PRETTY_PRINT
bool "Decode registers during diagnostics"
- depends on SCSI_AIC79XX
+ depends on SCSI_AIC79XX && SCSI_AIC7XXX_BUILD_FIRMWARE
default y
help
Compile in register value tables for the output of expanded register
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 760f98082ad2..9d9a9e4b02c7 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -92,7 +92,7 @@ config AIC7XXX_DEBUG_MASK
config AIC7XXX_REG_PRETTY_PRINT
bool "Decode registers during diagnostics"
- depends on SCSI_AIC7XXX
+ depends on SCSI_AIC7XXX && SCSI_AIC7XXX_BUILD_FIRMWARE
default y
help
Compile in register value tables for the output of expanded register
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 3ab6a15e39ad..715365d8c02c 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -134,5 +134,18 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
return num;
}
-static Scsi_Host_Template driver_template = AMIGA7XX_SCSI;
+static Scsi_Host_Template driver_template = {
+ .name = "Amiga NCR53c710 SCSI",
+ .detect = amiga7xx_detect,
+ .queuecommand = NCR53c7xx_queue_command,
+ .abort = NCR53c7xx_abort,
+ .reset = NCR53c7xx_reset,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+ .cmd_per_lun = 3,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
+
#include "scsi_module.c"
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index d563ac5a7b82..80da6a8261fe 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -24,15 +24,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
#include <scsi/scsicam.h>
-#define AMIGA7XX_SCSI {.name = "Amiga NCR53c710 SCSI", \
- .detect = amiga7xx_detect, \
- .queuecommand = NCR53c7xx_queue_command, \
- .abort = NCR53c7xx_abort, \
- .reset = NCR53c7xx_reset, \
- .can_queue = 24, \
- .this_id = 7, \
- .sg_tablesize = 63, \
- .cmd_per_lun = 3, \
- .use_clustering = DISABLE_CLUSTERING }
-
#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 537e3a6f448f..70da49bc0372 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -315,7 +315,7 @@ static Scsi_Host_Template *the_template = NULL;
#endif
typedef struct {
- char allocated[MAX_TAGS/8];
+ long allocated[MAX_TAGS/32];
int nr_allocated;
int queue_size;
} TAG_ALLOC;
@@ -561,14 +561,13 @@ static void NCR5380_print(struct Scsi_Host *instance) {
unsigned char status, data, basr, mr, icr, i;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
- restore_flags(flags);
+ local_irq_restore(flags);
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask ; ++i)
if (status & signals[i].mask)
@@ -769,9 +768,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset,
} \
} while (0)
- for (instance = first_instance; instance && HOSTNO != hostno;
- instance = instance->next)
- ;
+ instance = scsi_host_hn_get(hostno);
if (!instance)
return(-ESRCH);
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
@@ -781,8 +778,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset,
}
SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
check_offset();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
check_offset();
if (!hostdata->connected)
@@ -805,7 +801,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset,
check_offset();
}
- restore_flags(flags);
+ local_irq_restore(flags);
*start = buffer + (offset - begin);
if (pos - buffer < offset - begin)
return 0;
@@ -979,8 +975,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* sense data is only guaranteed to be valid while the condition exists.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
* Otherwise a running NCR5380_main may steal the lock.
* Lock before actually inserting due to fairness reasons explained in
@@ -1009,7 +1004,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
LIST(cmd, tmp);
NEXT(tmp) = cmd;
}
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
@@ -1073,9 +1068,9 @@ static void NCR5380_main (void)
return;
main_running = 1;
- save_flags(flags);
+ local_save_flags(flags);
do {
- cli(); /* Freeze request queues */
+ local_irq_disable(); /* Freeze request queues */
done = 1;
if (!hostdata->connected) {
@@ -1109,7 +1104,8 @@ static void NCR5380_main (void)
!(hostdata->busy[tmp->target] & (1 << tmp->lun))
#endif
) {
- cli(); /* ++guenther: just to be sure, this must be atomic */
+ /* ++guenther: just to be sure, this must be atomic */
+ local_irq_disable();
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
NEXT(prev) = NEXT(tmp);
@@ -1121,7 +1117,7 @@ static void NCR5380_main (void)
falcon_dont_release++;
/* reenable interrupts after finding one */
- restore_flags(flags);
+ local_irq_restore(flags);
/*
* Attempt to establish an I_T_L nexus here.
@@ -1153,7 +1149,7 @@ static void NCR5380_main (void)
falcon_release_lock_if_possible( hostdata );
break;
} else {
- cli();
+ local_irq_disable();
LIST(tmp, hostdata->issue_queue);
NEXT(tmp) = hostdata->issue_queue;
hostdata->issue_queue = tmp;
@@ -1161,7 +1157,7 @@ static void NCR5380_main (void)
cmd_free_tag( tmp );
#endif
falcon_dont_release--;
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main(): select() failed, "
"returned to issue_queue\n", HOSTNO);
if (hostdata->connected)
@@ -1176,7 +1172,7 @@ static void NCR5380_main (void)
&& !hostdata->dma_len
#endif
) {
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main: performing information transfer\n",
HOSTNO);
NCR5380_information_transfer(instance);
@@ -1189,7 +1185,7 @@ static void NCR5380_main (void)
an interrupt could believe we'll pick up the work it left for
us, but we won't see it anymore here... */
main_running = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1430,10 +1426,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* data bus during SELECTION.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -1446,7 +1441,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
- restore_flags(flags);
+ local_irq_restore(flags);
/* Wait for arbitration logic to complete */
#if NCR_TIMEOUT
@@ -1954,12 +1949,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- restore_flags(flags);
+ local_irq_restore(flags);
}
if (p & SR_IO)
@@ -1973,12 +1967,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
/* On the Falcon, the DMA setup must be done after the last */
/* NCR access, else the DMA setup gets trashed!
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- restore_flags(flags);
+ local_irq_restore(flags);
}
return 0;
}
@@ -2259,12 +2252,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->request_buffer = (char *) cmd->sense_buffer;
cmd->request_bufflen = sizeof(cmd->sense_buffer);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
NEXT(cmd) = hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
} else
@@ -2321,14 +2313,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
cmd->device->disconnect = 1;
LIST(cmd,hostdata->disconnected_queue);
NEXT(cmd) = hostdata->disconnected_queue;
hostdata->connected = NULL;
hostdata->disconnected_queue = cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
@@ -2671,8 +2662,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
NCR5380_print_status (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!IS_A_TT() && !falcon_got_lock)
printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
@@ -2718,12 +2708,12 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
cmd->scsi_done(cmd);
falcon_release_lock_if_possible( hostdata );
return SCSI_ABORT_SUCCESS;
} else {
-/* restore_flags(flags); */
+/* local_irq_restore(flags); */
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return SCSI_ABORT_ERROR;
}
@@ -2742,7 +2732,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
(*prev) = NEXT(tmp);
NEXT(tmp) = NULL;
tmp->result = DID_ABORT << 16;
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
@@ -2764,7 +2754,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
*/
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
return SCSI_ABORT_SNOOZE;
}
@@ -2797,7 +2787,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp))
if (cmd == tmp) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
if (NCR5380_select (instance, cmd, (int) cmd->tag))
@@ -2807,8 +2797,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
do_abort (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
@@ -2826,7 +2815,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
tmp->scsi_done(tmp);
falcon_release_lock_if_possible( hostdata );
return SCSI_ABORT_SUCCESS;
@@ -2843,7 +2832,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
* broke.
*/
- restore_flags(flags);
+ local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
KERN_INFO " before abortion\n", HOSTNO);
@@ -2906,8 +2895,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
* into the issue_queue (via scsi_done()), the aborted commands are
* remembered in local variables first.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
connected = (Scsi_Cmnd *)hostdata->connected;
hostdata->connected = NULL;
disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
@@ -2920,7 +2908,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* In order to tell the mid-level code which commands were aborted,
* set the command status to DID_RESET and call scsi_done() !!!
@@ -2986,8 +2974,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
if (hostdata->disconnected_queue)
ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->issue_queue = NULL;
hostdata->connected = NULL;
hostdata->disconnected_queue = NULL;
@@ -2999,7 +2986,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* we did no complete reset of all commands, so a wakeup is required */
return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 8572300a1282..07c40bd87e67 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -508,12 +508,11 @@ static int falcon_dont_release = 0;
static void
falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
{
- unsigned long oldflags;
+ unsigned long flags;
if (IS_A_TT()) return;
- save_flags(oldflags);
- cli();
+ local_irq_save(flags);
if (falcon_got_lock &&
!hostdata->disconnected_queue &&
@@ -524,7 +523,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
#if 0
printk("WARNING: Lock release not allowed. Ignored\n");
#endif
- restore_flags(oldflags);
+ local_irq_restore(flags);
return;
}
falcon_got_lock = 0;
@@ -532,7 +531,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
wake_up( &falcon_fairness_wait );
}
- restore_flags(oldflags);
+ local_irq_restore(flags);
}
/* This function manages the locking of the ST-DMA.
@@ -552,12 +551,11 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
static void falcon_get_lock( void )
{
- unsigned long oldflags;
+ unsigned long flags;
if (IS_A_TT()) return;
- save_flags(oldflags);
- cli();
+ local_irq_save(flags);
while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
sleep_on( &falcon_fairness_wait );
@@ -577,7 +575,7 @@ static void falcon_get_lock( void )
}
}
- restore_flags(oldflags);
+ local_irq_restore(flags);
if (!falcon_got_lock)
panic("Falcon SCSI: someone stole the lock :-(\n");
}
@@ -1141,7 +1139,23 @@ static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value
#include "atari_NCR5380.c"
-static Scsi_Host_Template driver_template = ATARI_SCSI;
+static Scsi_Host_Template driver_template = {
+ .proc_info = atari_scsi_proc_info,
+ .name = "Atari native SCSI",
+ .detect = atari_scsi_detect,
+ .release = atari_scsi_release,
+ .info = atari_scsi_info,
+ .queuecommand = atari_scsi_queue_command,
+ .abort = atari_scsi_abort,
+ .reset = atari_scsi_reset,
+ .can_queue = 0, /* initialized at run-time */
+ .this_id = 0, /* initialized at run-time */
+ .sg_tablesize = 0, /* initialized at run-time */
+ .cmd_per_lun = 0, /* initialized at run-time */
+ .use_clustering = DISABLE_CLUSTERING
+};
+
+
#include "scsi_module.c"
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index bab788445261..a6fd05a74d33 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -51,20 +51,6 @@ int atari_scsi_release (struct Scsi_Host *);
#define DEFAULT_USE_TAGGED_QUEUING 0
-#define ATARI_SCSI { .proc_info = atari_scsi_proc_info, \
- .name = "Atari native SCSI", \
- .detect = atari_scsi_detect, \
- .release = atari_scsi_release, \
- .info = atari_scsi_info, \
- .queuecommand = atari_scsi_queue_command, \
- .abort = atari_scsi_abort, \
- .reset = atari_scsi_reset, \
- .can_queue = 0, /* initialized at run-time */ \
- .this_id = 0, /* initialized at run-time */ \
- .sg_tablesize = 0, /* initialized at run-time */ \
- .cmd_per_lun = 0, /* initialized at run-time */ \
- .use_clustering = DISABLE_CLUSTERING }
-
#define NCR5380_implementation_fields /* none */
#define NCR5380_read(reg) atari_scsi_reg_read( reg )
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 90221a640e15..57296ffd25af 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -25,11 +25,11 @@
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "blz1230.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -40,6 +40,42 @@
#define MKIV 1
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ1230_ESP_ADDR 0x8000
+#define BLZ1230_DMA_ADDR 0x10000
+#define BLZ1230II_ESP_ADDR 0x10000
+#define BLZ1230II_DMA_ADDR 0x10021
+
+
+/* The Blizzard 1230 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ * 1) The data direction is controlled by the status of bit 31 (1 = write)
+ * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Program DMA by first latching the highest byte of the address/direction
+ * (i.e. bits 31-24 of the long word constructed as described in steps 1+2
+ * above). Then write each byte of the address/direction (starting with the
+ * top byte, working down) to the DMA address register.
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz1230_dma_registers {
+ volatile unsigned char dma_addr; /* DMA address [0x0000] */
+ unsigned char dmapad2[0x7fff];
+ volatile unsigned char dma_latch; /* DMA latch [0x8000] */
+};
+
+struct blz1230II_dma_registers {
+ volatile unsigned char dma_addr; /* DMA address [0x0000] */
+ unsigned char dmapad2[0xf];
+ volatile unsigned char dma_latch; /* DMA latch [0x0010] */
+};
+
+#define BLZ1230_DMA_WRITE 0x80000000
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_dump_state(struct NCR_ESP *esp);
@@ -279,12 +315,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
#define HOSTS_C
-#include "blz1230.h"
-
-static Scsi_Host_Template driver_template = SCSI_BLZ1230;
-
-#include "scsi_module.c"
-
int blz1230_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -297,4 +327,25 @@ int blz1230_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-blz1230",
+ .proc_info = esp_proc_info,
+ .name = "Blizzard1230 SCSI IV",
+ .detect = blz1230_esp_detect,
+ .release = blz1230_esp_release,
+ .command = esp_command,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/blz1230.h b/drivers/scsi/blz1230.h
deleted file mode 100644
index 233d500c9d9e..000000000000
--- a/drivers/scsi/blz1230.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* blz1230.h: Defines and structures for the Blizzard 1230 SCSI IV driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- *
- * This file is based on cyber_esp.h (hence the occasional reference to
- * CyberStorm).
- */
-
-#include "NCR53C9x.h"
-
-#ifndef BLZ1230_H
-#define BLZ1230_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define BLZ1230_ESP_ADDR 0x8000
-#define BLZ1230_DMA_ADDR 0x10000
-#define BLZ1230II_ESP_ADDR 0x10000
-#define BLZ1230II_DMA_ADDR 0x10021
-
-
-/* The Blizzard 1230 DMA interface
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Only two things can be programmed in the Blizzard DMA:
- * 1) The data direction is controlled by the status of bit 31 (1 = write)
- * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
- *
- * Program DMA by first latching the highest byte of the address/direction
- * (i.e. bits 31-24 of the long word constructed as described in steps 1+2
- * above). Then write each byte of the address/direction (starting with the
- * top byte, working down) to the DMA address register.
- *
- * Figure out interrupt status by reading the ESP status byte.
- */
-struct blz1230_dma_registers {
- volatile unsigned char dma_addr; /* DMA address [0x0000] */
- unsigned char dmapad2[0x7fff];
- volatile unsigned char dma_latch; /* DMA latch [0x8000] */
-};
-
-struct blz1230II_dma_registers {
- volatile unsigned char dma_addr; /* DMA address [0x0000] */
- unsigned char dmapad2[0xf];
- volatile unsigned char dma_latch; /* DMA latch [0x0010] */
-};
-
-#define BLZ1230_DMA_WRITE 0x80000000
-
-extern int blz1230_esp_detect(struct SHT *);
-extern int blz1230_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_BLZ1230 { .proc_name = "esp-blz1230", \
- .proc_info = esp_proc_info, \
- .name = "Blizzard1230 SCSI IV", \
- .detect = blz1230_esp_detect, \
- .release = blz1230_esp_release, \
- .command = esp_command, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* BLZ1230_H */
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index f5007bc6b697..07a9220816a3 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -25,11 +25,11 @@
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "blz2060.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -38,6 +38,38 @@
#include <asm/pgtable.h>
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ2060_ESP_ADDR 0x1ff00
+#define BLZ2060_DMA_ADDR 0x1ffe0
+
+
+/* The Blizzard 2060 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ * 1) The data direction is controlled by the status of bit 31 (1 = write)
+ * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz2060_dma_registers {
+ volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */
+ unsigned char dmapad1[0x0f];
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */
+ unsigned char dmapad2[0x03];
+ volatile unsigned char dma_addr1; /* DMA address [0x014] */
+ unsigned char dmapad3[0x03];
+ volatile unsigned char dma_addr2; /* DMA address [0x018] */
+ unsigned char dmapad4[0x03];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */
+};
+
+#define BLZ2060_DMA_WRITE 0x80000000
+
+/* DMA control bits */
+#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_dump_state(struct NCR_ESP *esp);
@@ -236,12 +268,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
#define HOSTS_C
-#include "blz2060.h"
-
-static Scsi_Host_Template driver_template = SCSI_BLZ2060;
-
-#include "scsi_module.c"
-
int blz2060_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -255,4 +281,24 @@ int blz2060_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-blz2060",
+ .proc_info = esp_proc_info,
+ .name = "Blizzard2060 SCSI",
+ .detect = blz2060_esp_detect,
+ .release = blz2060_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/blz2060.h b/drivers/scsi/blz2060.h
deleted file mode 100644
index ca119b9e6d67..000000000000
--- a/drivers/scsi/blz2060.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* blz2060.h: Defines and structures for the Blizzard 2060 SCSI driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- *
- * This file is based on cyber_esp.h (hence the occasional reference to
- * CyberStorm).
- */
-
-#include "NCR53C9x.h"
-
-#ifndef BLZ2060_H
-#define BLZ2060_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define BLZ2060_ESP_ADDR 0x1ff00
-#define BLZ2060_DMA_ADDR 0x1ffe0
-
-
-/* The Blizzard 2060 DMA interface
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Only two things can be programmed in the Blizzard DMA:
- * 1) The data direction is controlled by the status of bit 31 (1 = write)
- * 2) The source/dest address (word aligned, shifted one right) in bits 30-0
- *
- * Figure out interrupt status by reading the ESP status byte.
- */
-struct blz2060_dma_registers {
- volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */
- unsigned char dmapad1[0x0f];
- volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */
- unsigned char dmapad2[0x03];
- volatile unsigned char dma_addr1; /* DMA address [0x014] */
- unsigned char dmapad3[0x03];
- volatile unsigned char dma_addr2; /* DMA address [0x018] */
- unsigned char dmapad4[0x03];
- volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */
-};
-
-#define BLZ2060_DMA_WRITE 0x80000000
-
-/* DMA control bits */
-#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */
-
-extern int blz2060_esp_detect(struct SHT *);
-extern int blz2060_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_BLZ2060 { .proc_name = "esp-blz2060", \
- .proc_info = esp_proc_info, \
- .name = "Blizzard2060 SCSI", \
- .detect = blz2060_esp_detect, \
- .release = blz2060_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* BLZ2060_H */
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
index 75b99d4a257e..9f7ba7890ad1 100644
--- a/drivers/scsi/bvme6000.c
+++ b/drivers/scsi/bvme6000.c
@@ -51,5 +51,18 @@ int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
return 1;
}
-static Scsi_Host_Template driver_template = BVME6000_SCSI;
+static Scsi_Host_Template driver_template = {
+ .name = "BVME6000 NCR53c710 SCSI",
+ .detect = bvme6000_scsi_detect,
+ .queuecommand = NCR53c7xx_queue_command,
+ .abort = NCR53c7xx_abort,
+ .reset = NCR53c7xx_reset,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+ .cmd_per_lun = 3,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
+
#include "scsi_module.c"
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
index a1bfe3b0e06c..61dd486b9677 100644
--- a/drivers/scsi/bvme6000.h
+++ b/drivers/scsi/bvme6000.h
@@ -25,15 +25,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
#include <scsi/scsicam.h>
-#define BVME6000_SCSI {.name = "BVME6000 NCR53c710 SCSI", \
- .detect = bvme6000_scsi_detect, \
- .queuecommand = NCR53c7xx_queue_command, \
- .abort = NCR53c7xx_abort, \
- .reset = NCR53c7xx_reset, \
- .can_queue = 24, \
- .this_id = 7, \
- .sg_tablesize = 63, \
- .cmd_per_lun = 3, \
- .use_clustering = DISABLE_CLUSTERING }
-
#endif /* BVME6000_SCSI_H */
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index bb1fa3cf7cc2..83a3a0a9e5da 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -28,11 +28,11 @@
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "cyberstorm.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -41,6 +41,43 @@
#include <asm/pgtable.h>
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBER_ESP_ADDR 0xf400
+#define CYBER_DMA_ADDR 0xf800
+
+
+/* The CyberStorm DMA interface */
+struct cyber_dma_registers {
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */
+ unsigned char dmapad1[1];
+ volatile unsigned char dma_addr1; /* DMA address [0x002] */
+ unsigned char dmapad2[1];
+ volatile unsigned char dma_addr2; /* DMA address [0x004] */
+ unsigned char dmapad3[1];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */
+ unsigned char dmapad4[0x3fb];
+ volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */
+};
+
+/* DMA control bits */
+#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */
+#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */
+#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
+
+/* DMA status bits */
+#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */
+
+/* The bits below appears to be Phase5 Debug bits only; they were not
+ * described by Phase5 so using them may seem a bit stupid...
+ */
+#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise
+ * it should be 6.
+ */
+#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_dump_state(struct NCR_ESP *esp);
@@ -302,12 +339,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
#define HOSTS_C
-#include "cyberstorm.h"
-
-static Scsi_Host_Template driver_template = SCSI_CYBERSTORM;
-
-#include "scsi_module.c"
-
int cyber_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -321,4 +352,24 @@ int cyber_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-cyberstorm",
+ .proc_info = esp_proc_info,
+ .name = "CyberStorm SCSI",
+ .detect = cyber_esp_detect,
+ .release = cyber_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/cyberstorm.h b/drivers/scsi/cyberstorm.h
deleted file mode 100644
index bbae3199b0ac..000000000000
--- a/drivers/scsi/cyberstorm.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* cyberstorm.h: Defines and structures for the CyberStorm SCSI driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- */
-
-#include "NCR53C9x.h"
-
-#ifndef CYBER_ESP_H
-#define CYBER_ESP_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define CYBER_ESP_ADDR 0xf400
-#define CYBER_DMA_ADDR 0xf800
-
-
-/* The CyberStorm DMA interface */
-struct cyber_dma_registers {
- volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */
- unsigned char dmapad1[1];
- volatile unsigned char dma_addr1; /* DMA address [0x002] */
- unsigned char dmapad2[1];
- volatile unsigned char dma_addr2; /* DMA address [0x004] */
- unsigned char dmapad3[1];
- volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */
- unsigned char dmapad4[0x3fb];
- volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */
-#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */
-};
-
-/* DMA control bits */
-#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */
-#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */
-#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
-
-/* DMA status bits */
-#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */
-
-/* The bits below appears to be Phase5 Debug bits only; they were not
- * described by Phase5 so using them may seem a bit stupid...
- */
-#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise
- * it should be 6.
- */
-#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */
-
-extern int cyber_esp_detect(struct SHT *);
-extern int cyber_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-
-#define SCSI_CYBERSTORM { .proc_name = "esp-cyberstorm", \
- .proc_info = esp_proc_info, \
- .name = "CyberStorm SCSI", \
- .detect = cyber_esp_detect, \
- .release = cyber_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* CYBER_ESP_H */
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index d35b853b7ab4..25eb423ce467 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -24,11 +24,11 @@
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "cyberstormII.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -37,6 +37,30 @@
#include <asm/pgtable.h>
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBERII_ESP_ADDR 0x1ff03
+#define CYBERII_DMA_ADDR 0x1ff43
+
+
+/* The CyberStorm II DMA interface */
+struct cyberII_dma_registers {
+ volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */
+ unsigned char dmapad4[0x3f];
+ volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */
+ unsigned char dmapad1[3];
+ volatile unsigned char dma_addr1; /* DMA address [0x044] */
+ unsigned char dmapad2[3];
+ volatile unsigned char dma_addr2; /* DMA address [0x048] */
+ unsigned char dmapad3[3];
+ volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */
+};
+
+/* DMA control bits */
+#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_dump_state(struct NCR_ESP *esp);
@@ -252,13 +276,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
#define HOSTS_C
-#include "cyberstormII.h"
-
-static Scsi_Host_Template driver_template = SCSI_CYBERSTORMII;
-
-#include "scsi_module.c"
-
-
int cyberII_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -272,4 +289,24 @@ int cyberII_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-cyberstormII",
+ .proc_info = esp_proc_info,
+ .name = "CyberStorm Mk II SCSI",
+ .detect = cyberII_esp_detect,
+ .release = cyberII_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/cyberstormII.h b/drivers/scsi/cyberstormII.h
deleted file mode 100644
index 4a6bc0d9bf01..000000000000
--- a/drivers/scsi/cyberstormII.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* cyberstormII.h: Defines and structures for the CyberStorm SCSI Mk II driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- */
-
-#include "NCR53C9x.h"
-
-#ifndef CYBERII_ESP_H
-#define CYBERII_ESP_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define CYBERII_ESP_ADDR 0x1ff03
-#define CYBERII_DMA_ADDR 0x1ff43
-
-
-/* The CyberStorm II DMA interface */
-struct cyberII_dma_registers {
- volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */
-#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */
- unsigned char dmapad4[0x3f];
- volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */
- unsigned char dmapad1[3];
- volatile unsigned char dma_addr1; /* DMA address [0x044] */
- unsigned char dmapad2[3];
- volatile unsigned char dma_addr2; /* DMA address [0x048] */
- unsigned char dmapad3[3];
- volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */
-};
-
-/* DMA control bits */
-#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */
-
-
-extern int cyberII_esp_detect(struct SHT *);
-extern int cyberII_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_CYBERSTORMII { .proc_name = "esp-cyberstormII", \
- .proc_info = esp_proc_info, \
- .name = "CyberStorm Mk II SCSI", \
- .detect = cyberII_esp_detect, \
- .release = cyberII_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* CYBERII_ESP_H */
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index 23eabb24f434..b932a401df4f 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -31,7 +31,6 @@
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "dec_esp.h"
#include <asm/irq.h>
#include <asm/jazz.h>
@@ -46,6 +45,11 @@
#include <asm/dec/ioasic_ints.h>
#include <asm/dec/machtype.h>
+#define DEC_SCSI_SREG 0
+#define DEC_SCSI_DMAREG 0x40000
+#define DEC_SCSI_SRAM 0x80000
+#define DEC_SCSI_DIAG 0xC0000
+
/*
* Once upon a time the pmaz code used to be working but
* it hasn't been maintained for quite some time.
@@ -103,7 +107,25 @@ volatile unsigned long *scsi_sdr1;
static void scsi_dma_int(int, void *, struct pt_regs *);
-static Scsi_Host_Template driver_template = SCSI_DEC_ESP;
+int dec_esp_detect(Scsi_Host_Template * tpnt);
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp",
+ .proc_info = &esp_proc_info,
+ .name = "NCR53C94",
+ .detect = dec_esp_detect,
+ .info = esp_info,
+ .command = esp_command,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/dec_esp.h b/drivers/scsi/dec_esp.h
deleted file mode 100644
index 6c428b553777..000000000000
--- a/drivers/scsi/dec_esp.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* dec_esp.h: Defines and structures for the JAZZ SCSI driver.
- *
- * DECstation changes Copyright (C) 1998 Harald Koerfgen
- * and David Airlie
- *
- * based on jazz_esp.h:
- * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- */
-
-#ifndef DEC_ESP_H
-#define DEC_ESP_H
-
-#include "NCR53C9x.h"
-
-#define DEC_SCSI_SREG 0
-#define DEC_SCSI_DMAREG 0x40000
-#define DEC_SCSI_SRAM 0x80000
-#define DEC_SCSI_DIAG 0xC0000
-
-extern int dec_esp_detect(struct SHT *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_DEC_ESP { \
- .proc_name = "esp", \
- .proc_info = &esp_proc_info, \
- .name = "NCR53C94", \
- .detect = dec_esp_detect, \
- .info = esp_info, \
- .command = esp_command, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = DISABLE_CLUSTERING, }
-
-#endif /* DEC_ESP_H */
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index b30cf21c8a91..b58c0289ea14 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -33,11 +33,11 @@
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "fastlane.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -53,6 +53,36 @@
#define NODMAIRQ
#endif
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define FASTLANE_ESP_ADDR 0x1000001
+#define FASTLANE_DMA_ADDR 0x1000041
+
+
+/* The Fastlane DMA interface */
+struct fastlane_dma_registers {
+ volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */
+#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */
+ unsigned char dmapad1[0x3f];
+ volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */
+};
+
+
+/* DMA status bits */
+#define FASTLANE_DMA_MINT 0x80
+#define FASTLANE_DMA_IACT 0x40
+#define FASTLANE_DMA_CREQ 0x20
+
+/* DMA control bits */
+#define FASTLANE_DMA_FCODE 0xa0
+#define FASTLANE_DMA_MASK 0xf3
+#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */
+#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */
+#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */
+#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */
+#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static inline void dma_clear(struct NCR_ESP *esp);
@@ -140,7 +170,7 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt)
/* Map the physical address space into virtual kernel space */
address = (unsigned long)
- ioremap_nocache(board, z->resource.end-board+1);
+ z_ioremap(board, z->resource.end-board+1);
if(!address){
printk("Could not remap Fastlane controller memory!");
@@ -189,7 +219,7 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt)
return 0;
err_unmap:
- iounmap((void *)address);
+ z_iounmap((void *)address);
err_unregister:
scsi_unregister (esp->ehost);
err_release:
@@ -356,11 +386,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
#define HOSTS_C
-#include "fastlane.h"
-
-static Scsi_Host_Template driver_template = SCSI_FASTLANE;
-#include "scsi_module.c"
-
int fastlane_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -373,4 +398,23 @@ int fastlane_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-fastlane",
+ .proc_info = esp_proc_info,
+ .name = "Fastlane SCSI",
+ .detect = fastlane_esp_detect,
+ .release = fastlane_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fastlane.h b/drivers/scsi/fastlane.h
deleted file mode 100644
index 57e956cf539a..000000000000
--- a/drivers/scsi/fastlane.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* fastlane.h: Defines and structures for the Fastlane SCSI driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- */
-
-#include "NCR53C9x.h"
-
-#ifndef FASTLANE_H
-#define FASTLANE_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define FASTLANE_ESP_ADDR 0x1000001
-#define FASTLANE_DMA_ADDR 0x1000041
-
-
-/* The Fastlane DMA interface */
-struct fastlane_dma_registers {
- volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */
-#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */
- unsigned char dmapad1[0x3f];
- volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */
-};
-
-
-/* DMA status bits */
-#define FASTLANE_DMA_MINT 0x80
-#define FASTLANE_DMA_IACT 0x40
-#define FASTLANE_DMA_CREQ 0x20
-
-/* DMA control bits */
-#define FASTLANE_DMA_FCODE 0xa0
-#define FASTLANE_DMA_MASK 0xf3
-#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */
-#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */
-#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */
-#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */
-#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */
-
-extern int fastlane_esp_detect(struct SHT *);
-extern int fastlane_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_FASTLANE { .proc_name = "esp-fastlane", \
- .proc_info = esp_proc_info, \
- .name = "Fastlane SCSI", \
- .detect = fastlane_esp_detect, \
- .release = fastlane_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* FASTLANE_H */
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 5dece79737d7..ad2d6c301d30 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -355,7 +356,21 @@ release:
#include "gvp11.h"
-static Scsi_Host_Template driver_template = GVP11_SCSI;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "GVP11",
+ .name = "GVP Series II SCSI",
+ .detect = gvp11_detect,
+ .release = gvp11_release,
+ .queuecommand = wd33c93_queuecommand,
+ .abort = wd33c93_abort,
+ .reset = wd33c93_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
index d95b1a63726d..c60eedbee117 100644
--- a/drivers/scsi/gvp11.h
+++ b/drivers/scsi/gvp11.h
@@ -30,21 +30,7 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#define CAN_QUEUE 16
#endif
-#ifdef HOSTS_C
-
-#define GVP11_SCSI { .proc_name = "GVP11", \
- .name = "GVP Series II SCSI", \
- .detect = gvp11_detect, \
- .release = gvp11_release, \
- .queuecommand = wd33c93_queuecommand, \
- .abort = wd33c93_abort, \
- .reset = wd33c93_reset, \
- .can_queue = CAN_QUEUE, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = CMD_PER_LUN, \
- .use_clustering = DISABLE_CLUSTERING }
-#else
+#ifndef HOSTS_C
/*
* if the transfer address ANDed with this results in a non-zero
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 108bb4292725..29e0115ad68d 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -18,7 +18,6 @@
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "jazz_esp.h"
#include <asm/irq.h>
#include <asm/jazz.h>
@@ -273,3 +272,21 @@ static void dma_led_on(struct NCR_ESP *esp)
*(unsigned char *)JAZZ_HDC_LED = 1;
#endif
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp",
+ .proc_info = &esp_proc_info,
+ .name = "ESP 100/100a/200",
+ .detect = jazz_esp_detect,
+ .info = esp_info,
+ .command = esp_command,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+};
+
diff --git a/drivers/scsi/jazz_esp.h b/drivers/scsi/jazz_esp.h
deleted file mode 100644
index 0f95410ed9a7..000000000000
--- a/drivers/scsi/jazz_esp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* jazz_esp.h: Defines and structures for the JAZZ SCSI driver.
- *
- * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- */
-
-#ifndef JAZZ_ESP_H
-#define JAZZ_ESP_H
-
-#define EREGS_PAD(n)
-
-#include "NCR53C9x.h"
-
-
-extern int jazz_esp_detect(struct SHT *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_JAZZ_ESP { \
- .proc_name = "esp", \
- .proc_info = &esp_proc_info, \
- .name = "ESP 100/100a/200", \
- .detect = jazz_esp_detect, \
- .info = esp_info, \
- .command = esp_command, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = DISABLE_CLUSTERING, }
-
-#endif /* JAZZ_ESP_H */
diff --git a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c
index 521338547345..2fe5a1c5b76e 100644
--- a/drivers/scsi/mac_NCR5380.c
+++ b/drivers/scsi/mac_NCR5380.c
@@ -578,14 +578,13 @@ static void NCR5380_print(struct Scsi_Host *instance) {
unsigned char status, data, basr, mr, icr, i;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
- restore_flags(flags);
+ local_irq_restore(flags);
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask ; ++i)
if (status & signals[i].mask)
@@ -801,8 +800,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset,
}
SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
check_offset();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
check_offset();
if (!hostdata->connected)
@@ -825,7 +823,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset,
check_offset();
}
- restore_flags(flags);
+ local_irq_restore(flags);
*start = buffer + (offset - begin);
if (pos - buffer < offset - begin)
return 0;
@@ -999,8 +997,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* sense data is only guaranteed to be valid while the condition exists.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
LIST(cmd, hostdata->issue_queue);
@@ -1013,7 +1010,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
LIST(cmd, tmp);
NEXT(tmp) = cmd;
}
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
@@ -1077,9 +1074,9 @@ static void NCR5380_main (void)
return;
main_running = 1;
- save_flags(flags);
+ local_save_flags(flags);
do {
- cli(); /* Freeze request queues */
+ local_irq_disable(); /* Freeze request queues */
done = 1;
if (!hostdata->connected) {
@@ -1112,7 +1109,8 @@ static void NCR5380_main (void)
!(hostdata->busy[tmp->target] & (1 << tmp->lun))
#endif
) {
- cli(); /* ++guenther: just to be sure, this must be atomic */
+ /* ++guenther: just to be sure, this must be atomic */
+ local_irq_disable();
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
NEXT(prev) = NEXT(tmp);
@@ -1123,7 +1121,7 @@ static void NCR5380_main (void)
NEXT(tmp) = NULL;
/* reenable interrupts after finding one */
- restore_flags(flags);
+ local_irq_restore(flags);
/*
* Attempt to establish an I_T_L nexus here.
@@ -1152,14 +1150,14 @@ static void NCR5380_main (void)
TAG_NEXT)) {
break;
} else {
- cli();
+ local_irq_disable();
LIST(tmp, hostdata->issue_queue);
NEXT(tmp) = hostdata->issue_queue;
hostdata->issue_queue = tmp;
#ifdef SUPPORT_TAGS
cmd_free_tag( tmp );
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main(): select() failed, "
"returned to issue_queue\n", HOSTNO);
if (hostdata->connected)
@@ -1174,7 +1172,7 @@ static void NCR5380_main (void)
&& !hostdata->dma_len
#endif
) {
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main: performing information transfer\n",
HOSTNO);
NCR5380_information_transfer(instance);
@@ -1187,7 +1185,7 @@ static void NCR5380_main (void)
an interrupt could believe we'll pick up the work it left for
us, but we won't see it anymore here... */
main_running = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1428,10 +1426,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* data bus during SELECTION.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -1444,7 +1441,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
- restore_flags(flags);
+ local_irq_restore(flags);
/* Wait for arbitration logic to complete */
#if NCR_TIMEOUT
@@ -1950,8 +1947,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
#else /* PSEUDO_DMA! */
#if defined(PSEUDO_DMA) && !defined(UNSAFE)
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#endif
/* KLL May need eop and parity in 53c400 */
if (hostdata->flags & FLAG_NCR53C400)
@@ -1970,12 +1966,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- restore_flags(flags);
+ local_irq_restore(flags);
#endif /* def REAL_DMA */
#ifndef EMULATE_PSEUDO_DMA
@@ -2120,7 +2115,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
NCR5380_print_phase(instance);
#endif
#if defined(PSEUDO_DMA) && !defined(UNSAFE)
- restore_flags(flags);
+ local_irq_restore(flags);
#endif /* defined(REAL_DMA_POLL) */
return foo;
#endif /* def REAL_DMA */
@@ -2410,12 +2405,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->request_buffer = (char *) cmd->sense_buffer;
cmd->request_bufflen = sizeof(cmd->sense_buffer);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
NEXT(cmd) = hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
} else
@@ -2466,14 +2460,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
cmd->device->disconnect = 1;
LIST(cmd,hostdata->disconnected_queue);
NEXT(cmd) = hostdata->disconnected_queue;
hostdata->connected = NULL;
hostdata->disconnected_queue = cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
@@ -2812,8 +2805,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
NCR5380_print_status (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
NCR5380_read(BUS_AND_STATUS_REG),
@@ -2855,11 +2847,11 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
cmd->scsi_done(cmd);
return SCSI_ABORT_SUCCESS;
} else {
-/* restore_flags(flags); */
+/* local_irq_restore(flags); */
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return SCSI_ABORT_ERROR;
}
@@ -2878,7 +2870,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
(*prev) = NEXT(tmp);
NEXT(tmp) = NULL;
tmp->result = DID_ABORT << 16;
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
@@ -2899,7 +2891,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
*/
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
return SCSI_ABORT_SNOOZE;
}
@@ -2932,7 +2924,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp))
if (cmd == tmp) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
if (NCR5380_select (instance, cmd, (int) cmd->tag))
@@ -2942,8 +2934,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
do_abort (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
@@ -2961,7 +2952,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
tmp->scsi_done(tmp);
return SCSI_ABORT_SUCCESS;
}
@@ -2977,7 +2968,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd)
* broke.
*/
- restore_flags(flags);
+ local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
KERN_INFO " before abortion\n", HOSTNO);
@@ -3035,8 +3026,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
* into the issue_queue (via scsi_done()), the aborted commands are
* remembered in local variables first.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
connected = (Scsi_Cmnd *)hostdata->connected;
hostdata->connected = NULL;
disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
@@ -3049,7 +3039,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* In order to tell the mid-level code which commands were aborted,
* set the command status to DID_RESET and call scsi_done() !!!
@@ -3108,8 +3098,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
if (hostdata->disconnected_queue)
ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->issue_queue = NULL;
hostdata->connected = NULL;
hostdata->disconnected_queue = NULL;
@@ -3121,14 +3110,28 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* we did no complete reset of all commands, so a wakeup is required */
return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
#endif /* 1 */
}
-static Scsi_Host_Template driver_template = MAC_NCR5380;
+static Scsi_Host_Template driver_template = {
+ .name = "Macintosh NCR5380 SCSI",
+ .detect = macscsi_detect,
+ .release = macscsi_release,
+ .info = macscsi_info,
+ .queuecommand = macscsi_queue_command,
+ .abort = macscsi_abort,
+ .reset = macscsi_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index dcaa2dbe8c3f..cc01741d1416 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -23,11 +23,11 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "mac_esp.h"
#include <asm/io.h>
@@ -41,6 +41,8 @@
#include <asm/macintosh.h>
+/* #define DEBUG_MAC_ESP */
+
#define mac_turnon_irq(x) mac_enable_irq(x)
#define mac_turnoff_irq(x) mac_disable_irq(x)
@@ -710,7 +712,22 @@ static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int wri
#endif
}
-static Scsi_Host_Template driver_template = SCSI_MAC_ESP;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp",
+ .name = "Mac 53C9x SCSI",
+ .detect = mac_esp_detect,
+ .info = esp_info,
+ /* .command = esp_command, */
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/mac_esp.h b/drivers/scsi/mac_esp.h
deleted file mode 100644
index c0113e76132a..000000000000
--- a/drivers/scsi/mac_esp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-
-/*
-mac_esp.h
-
-copyright 1997 David Weis, weisd3458@uni.edu
-*/
-
-
-#include "NCR53C9x.h"
-
-#ifndef MAC_ESP_H
-#define MAC_ESP_H
-
-/* #define DEBUG_MAC_ESP */
-
-extern int mac_esp_detect(struct SHT *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-
-
-#define SCSI_MAC_ESP { .proc_name = "esp", \
- .name = "Mac 53C9x SCSI", \
- .detect = mac_esp_detect, \
- .release = NULL, \
- .info = esp_info, \
- /* command: esp_command, */ \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = DISABLE_CLUSTERING }
-
-#endif /* MAC_ESP_H */
-
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index a1b77530096e..e045d02b5f83 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -370,9 +370,9 @@ void restore_irq(struct pt_regs *regs)
{
unsigned long flags;
- save_flags(flags);
+ local_save_flags(flags);
flags = (flags & ~0x0700) | (regs->sr & 0x0700);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -621,10 +621,9 @@ void scsi_mac_debug (void)
NCR5380_setup(default_instance);
if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
NCR5380_print_status(default_instance);
- restore_flags(flags);
+ local_irq_restore(flags);
}
#if 0
polled_scsi_on = 1;
@@ -651,10 +650,9 @@ void scsi_mac_polled (void)
if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
{
printk("SCSI poll\n");
- save_flags(flags);
- cli();
+ local_irq_save(flags);
NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
- restore_flags(flags);
+ local_irq_restore(flags);
}
#if 0
}
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index cbadd79b29ce..9918b52216da 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -44,13 +44,37 @@
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "mca_53c9x.h"
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/mca_dma.h>
#include <asm/pgtable.h>
+/*
+ * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk
+ * activity LED on and off
+ */
+
+#define PS2_SYS_CTR 0x92
+
+/* Ports the ncr's 53c94 can be put at; indexed by pos register value */
+
+#define MCA_53C9X_IO_PORTS { \
+ 0x0000, 0x0240, 0x0340, 0x0400, \
+ 0x0420, 0x3240, 0x8240, 0xA240, \
+ }
+
+/*
+ * Supposedly there were some cards put together with the 'c9x and 86c01. If
+ * they have different ID's from the ones on the 3500 series machines,
+ * you can add them here and hopefully things will work out.
+ */
+
+#define MCA_53C9X_IDS { \
+ 0x7F4C, \
+ 0x0000, \
+ }
+
static int dma_bytes_sent(struct NCR_ESP *, int);
static int dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *);
static void dma_dump_state(struct NCR_ESP *);
@@ -419,7 +443,22 @@ static void dma_led_off(struct NCR_ESP *esp)
outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
}
-static Scsi_Host_Template driver_template = MCA_53C9X;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp",
+ .name = "NCR 53c9x SCSI",
+ .detect = mca_esp_detect,
+ .release = mca_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .unchecked_isa_dma = 1,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
+
#include "scsi_module.c"
/*
diff --git a/drivers/scsi/mca_53c9x.h b/drivers/scsi/mca_53c9x.h
deleted file mode 100644
index 9b7b7df42ed8..000000000000
--- a/drivers/scsi/mca_53c9x.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* mca_53c94.h: Defines and structures for the SCSI adapter found on NCR 35xx
- * (and maybe some other) Microchannel machines.
- *
- * Code taken mostly from Cyberstorm SCSI drivers
- * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
- *
- * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
- * 1998
- */
-
-#include "NCR53C9x.h"
-
-#ifndef MCA_53C9X_H
-#define MCA_53C9X_H
-
-/*
- * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk
- * activity LED on and off
- */
-
-#define PS2_SYS_CTR 0x92
-
-extern int mca_esp_detect(struct SHT *);
-extern int mca_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-
-#define MCA_53C9X { .proc_name = "esp", \
- .name = "NCR 53c9x SCSI", \
- .detect = mca_esp_detect, \
- .release = mca_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .unchecked_isa_dma = 1, \
- .use_clustering = DISABLE_CLUSTERING }
-
-/* Ports the ncr's 53c94 can be put at; indexed by pos register value */
-
-#define MCA_53C9X_IO_PORTS { \
- 0x0000, 0x0240, 0x0340, 0x0400, \
- 0x0420, 0x3240, 0x8240, 0xA240, \
- }
-
-/*
- * Supposedly there were some cards put together with the 'c9x and 86c01. If
- * they have different ID's from the ones on the 3500 series machines,
- * you can add them here and hopefully things will work out.
- */
-
-#define MCA_53C9X_IDS { \
- 0x7F4C, \
- 0x0000, \
- }
-
-#endif /* MCA_53C9X_H */
-
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 81a2d699a821..5f081518ddce 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -3,6 +3,7 @@
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -115,7 +116,21 @@ int mvme147_detect(Scsi_Host_Template *tpnt)
#include "mvme147.h"
-static Scsi_Host_Template driver_template = MVME147_SCSI;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "MVME147",
+ .name = "MVME147 built-in SCSI",
+ .detect = mvme147_detect,
+ .release = mvme147_release,
+ .queuecommand = wd33c93_queuecommand,
+ .abort = wd33c93_abort,
+ .reset = wd33c93_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
index e68f86fdada0..264a9fdce90d 100644
--- a/drivers/scsi/mvme147.h
+++ b/drivers/scsi/mvme147.h
@@ -29,22 +29,4 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#define CAN_QUEUE 16
#endif
-#ifdef HOSTS_C
-
-#define MVME147_SCSI {.proc_name = "MVME147", \
- .proc_info = NULL, \
- .name = "MVME147 built-in SCSI", \
- .detect = mvme147_detect, \
- .release = mvme147_release, \
- .queuecommand = wd33c93_queuecommand, \
- .abort = wd33c93_abort, \
- .reset = wd33c93_reset, \
- .can_queue = CAN_QUEUE, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = CMD_PER_LUN, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* else def HOSTS_C */
-
#endif /* MVME147_H */
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index dc5052dbb1c4..45df12009189 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -53,5 +53,18 @@ int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
return 1;
}
-static Scsi_Host_Template driver_template = MVME16x_SCSI;
+static Scsi_Host_Template driver_template = {
+ .name = "MVME16x NCR53c710 SCSI",
+ .detect = mvme16x_scsi_detect,
+ .queuecommand = NCR53c7xx_queue_command,
+ .abort = NCR53c7xx_abort,
+ .reset = NCR53c7xx_reset,
+ .can_queue = 24,
+ .this_id = 7,
+ .sg_tablesize = 63,
+ .cmd_per_lun = 3,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
+
#include "scsi_module.c"
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
index 33e4225a5980..f2e56196aff2 100644
--- a/drivers/scsi/mvme16x.h
+++ b/drivers/scsi/mvme16x.h
@@ -25,15 +25,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
#include <scsi/scsicam.h>
-#define MVME16x_SCSI {.name = "MVME16x NCR53c710 SCSI", \
- .detect = mvme16x_scsi_detect, \
- .queuecommand = NCR53c7xx_queue_command, \
- .abort = NCR53c7xx_abort, \
- .reset = NCR53c7xx_reset, \
- .can_queue = 24, \
- .this_id = 7, \
- .sg_tablesize = 63, \
- .cmd_per_lun = 3, \
- .use_clustering = DISABLE_CLUSTERING }
-
#endif /* MVME16x_SCSI_H */
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index cef821562879..cda75b428d50 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -32,7 +32,6 @@
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "oktagon_esp.h"
#include <linux/zorro.h>
#include <asm/irq.h>
@@ -46,6 +45,13 @@
#include <linux/unistd.h>
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define OKTAGON_ESP_ADDR 0x03000
+#define OKTAGON_DMA_ADDR 0x01000
+
+
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_dump_state(struct NCR_ESP *esp);
@@ -571,12 +577,6 @@ void dma_advance_sg(Scsi_Cmnd *sp)
#define HOSTS_C
-#include "oktagon_esp.h"
-
-static Scsi_Host_Template driver_template = SCSI_OKTAGON_ESP;
-
-#include "scsi_module.c"
-
int oktagon_esp_release(struct Scsi_Host *instance)
{
#ifdef MODULE
@@ -589,4 +589,24 @@ int oktagon_esp_release(struct Scsi_Host *instance)
return 1;
}
+
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp-oktagon",
+ .proc_info = &esp_proc_info,
+ .name = "BSC Oktagon SCSI",
+ .detect = oktagon_esp_detect,
+ .release = oktagon_esp_release,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/oktagon_esp.h b/drivers/scsi/oktagon_esp.h
deleted file mode 100644
index f4ba3350c726..000000000000
--- a/drivers/scsi/oktagon_esp.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* oktagon_esp.h: Defines and structures for the CyberStorm SCSI Mk II driver.
- *
- * Copyright (C) 1996 Jesper Skov (jskov@cs.auc.dk)
- */
-
-#include "NCR53C9x.h"
-
-#ifndef OKTAGON_ESP_H
-#define OKTAGON_ESP_H
-
-/* The controller registers can be found in the Z2 config area at these
- * offsets:
- */
-#define OKTAGON_ESP_ADDR 0x03000
-#define OKTAGON_DMA_ADDR 0x01000
-
-
-/* The CyberStorm II DMA interface */
-struct oktagon_dma_registers {
- volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */
-#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */
- unsigned char dmapad4[0x3f];
- volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */
- unsigned char dmapad1[3];
- volatile unsigned char dma_addr1; /* DMA address [0x044] */
- unsigned char dmapad2[3];
- volatile unsigned char dma_addr2; /* DMA address [0x048] */
- unsigned char dmapad3[3];
- volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */
-};
-
-extern int oktagon_esp_detect(struct SHT *);
-extern int oktagon_esp_release(struct Scsi_Host *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define SCSI_OKTAGON_ESP { \
- .proc_name = "esp-oktagon", \
- .proc_info = &esp_proc_info, \
- .name = "BSC Oktagon SCSI", \
- .detect = oktagon_esp_detect, \
- .release = oktagon_esp_release, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = ENABLE_CLUSTERING }
-
-#endif /* OKTAGON_ESP_H */
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 1dd34aeb225e..62ee4cf8e5f3 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -567,14 +567,13 @@ static void NCR5380_print(struct Scsi_Host *instance) {
unsigned char status, data, basr, mr, icr, i;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
- restore_flags(flags);
+ local_irq_restore(flags);
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask ; ++i)
if (status & signals[i].mask)
@@ -772,9 +771,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset,
} \
} while (0)
- for (instance = first_instance; instance && HOSTNO != hostno;
- instance = instance->next)
- ;
+ instance = scsi_host_hn_get(hostno);
if (!instance)
return(-ESRCH);
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
@@ -784,8 +781,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset,
}
SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
check_offset();
- save_flags(flags);
- cli();
+ local_irq_save(flags);
SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
check_offset();
if (!hostdata->connected)
@@ -808,7 +804,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset,
check_offset();
}
- restore_flags(flags);
+ local_irq_restore(flags);
*start = buffer + (offset - begin);
if (pos - buffer < offset - begin)
return 0;
@@ -978,8 +974,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* sense data is only guaranteed to be valid while the condition exists.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
* Otherwise a running NCR5380_main may steal the lock.
* Lock before actually inserting due to fairness reasons explained in
@@ -1004,7 +999,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
NEXT(tmp) = cmd;
}
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
@@ -1068,9 +1063,9 @@ static void NCR5380_main (void)
return;
main_running = 1;
- save_flags(flags);
+ local_save_flags(flags);
do {
- cli(); /* Freeze request queues */
+ local_irq_disable(flags); /* Freeze request queues */
done = 1;
if (!hostdata->connected) {
@@ -1103,7 +1098,8 @@ static void NCR5380_main (void)
!(hostdata->busy[tmp->target] & (1 << tmp->lun))
#endif
) {
- cli(); /* ++guenther: just to be sure, this must be atomic */
+ /* ++guenther: just to be sure, this must be atomic */
+ local_irq_disable();
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
NEXT(prev) = NEXT(tmp);
@@ -1114,7 +1110,7 @@ static void NCR5380_main (void)
NEXT(tmp) = NULL;
/* reenable interrupts after finding one */
- restore_flags(flags);
+ local_irq_restore(flags);
/*
* Attempt to establish an I_T_L nexus here.
@@ -1143,14 +1139,14 @@ static void NCR5380_main (void)
TAG_NEXT)) {
break;
} else {
- cli();
+ local_irq_disable();
LIST(tmp, hostdata->issue_queue);
NEXT(tmp) = hostdata->issue_queue;
hostdata->issue_queue = tmp;
#ifdef SUPPORT_TAGS
cmd_free_tag( tmp );
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main(): select() failed, "
"returned to issue_queue\n", HOSTNO);
if (hostdata->connected)
@@ -1164,7 +1160,7 @@ static void NCR5380_main (void)
&& !hostdata->dma_len
#endif
) {
- restore_flags(flags);
+ local_irq_restore(flags);
MAIN_PRINTK("scsi%d: main: performing information transfer\n",
HOSTNO);
NCR5380_information_transfer(instance);
@@ -1177,7 +1173,7 @@ static void NCR5380_main (void)
an interrupt could believe we'll pick up the work it left for
us, but we won't see it anymore here... */
main_running = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1418,10 +1414,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* data bus during SELECTION.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
return -1;
}
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -1434,7 +1429,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
- restore_flags(flags);
+ local_irq_restore(flags);
/* Wait for arbitration logic to complete */
#if NCR_TIMEOUT
@@ -1931,8 +1926,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
c, (p & SR_IO) ? "to" : "from", *data);
/* netbsd turns off ints here, why not be safe and do it too */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* send start chain */
sun3scsi_dma_start(c, *data);
@@ -1955,7 +1949,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance,
dregs->csr |= CSR_DMA_ENABLE;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
sun3_dma_active = 1;
return 0;
@@ -2275,12 +2269,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->request_buffer = (char *) cmd->sense_buffer;
cmd->request_bufflen = sizeof(cmd->sense_buffer);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
NEXT(cmd) = hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
} else
@@ -2331,14 +2324,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
cmd->device->disconnect = 1;
LIST(cmd,hostdata->disconnected_queue);
NEXT(cmd) = hostdata->disconnected_queue;
hostdata->connected = NULL;
hostdata->disconnected_queue = cmd;
- restore_flags(flags);
+ local_irq_restore(flags);
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
@@ -2704,8 +2696,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
NCR5380_print_status (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
NCR5380_read(BUS_AND_STATUS_REG),
@@ -2747,11 +2738,11 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
cmd->scsi_done(cmd);
return SCSI_ABORT_SUCCESS;
} else {
-/* restore_flags(flags); */
+/* local_irq_restore(flags); */
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return SCSI_ABORT_ERROR;
}
@@ -2770,7 +2761,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
(*prev) = NEXT(tmp);
NEXT(tmp) = NULL;
tmp->result = DID_ABORT << 16;
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
@@ -2791,7 +2782,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
*/
if (hostdata->connected) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
return SCSI_ABORT_SNOOZE;
}
@@ -2824,7 +2815,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp))
if (cmd == tmp) {
- restore_flags(flags);
+ local_irq_restore(flags);
ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
if (NCR5380_select (instance, cmd, (int) cmd->tag))
@@ -2834,8 +2825,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
do_abort (instance);
- save_flags(flags);
- cli();
+ local_irq_save(flags);
for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
@@ -2853,7 +2843,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
tmp->scsi_done(tmp);
return SCSI_ABORT_SUCCESS;
}
@@ -2869,7 +2859,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
* broke.
*/
- restore_flags(flags);
+ local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
KERN_INFO " before abortion\n", HOSTNO);
@@ -2923,8 +2913,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
* into the issue_queue (via scsi_done()), the aborted commands are
* remembered in local variables first.
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
connected = (Scsi_Cmnd *)hostdata->connected;
hostdata->connected = NULL;
disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
@@ -2937,7 +2926,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* In order to tell the mid-level code which commands were aborted,
* set the command status to DID_RESET and call scsi_done() !!!
@@ -2997,8 +2986,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
if (hostdata->disconnected_queue)
ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
- save_flags(flags);
- cli();
+ local_irq_save(flags);
hostdata->issue_queue = NULL;
hostdata->connected = NULL;
hostdata->disconnected_queue = NULL;
@@ -3010,7 +2998,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
/* we did no complete reset of all commands, so a wakeup is required */
return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 502f764b4233..7fd253d96f8a 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -402,10 +402,9 @@ void sun3_sun3_debug (void)
NCR5380_local_declare();
if (default_instance) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
NCR5380_print_status(default_instance);
- restore_flags(flags);
+ local_irq_restore(flags);
}
}
#endif
@@ -616,7 +615,21 @@ static int sun3scsi_dma_finish(int write_flag)
#include "sun3_NCR5380.c"
-static Scsi_Host_Template driver_template = SUN3_NCR5380;
+static Scsi_Host_Template driver_template = {
+ .name = SUN3_SCSI_NAME,
+ .detect = sun3scsi_detect,
+ .release = sun3scsi_release,
+ .info = sun3scsi_info,
+ .queuecommand = sun3scsi_queue_command,
+ .abort = sun3scsi_abort,
+ .reset = sun3scsi_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_TABLESIZE,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index 230f8c31c9ab..b7a569b3d2bb 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -93,22 +93,6 @@ static int sun3scsi_release (struct Scsi_Host *);
#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
#endif
-#define SUN3_NCR5380 { \
-.name = SUN3_SCSI_NAME, \
-.detect = sun3scsi_detect, \
-.release = sun3scsi_release, /* Release */ \
-.info = sun3scsi_info, \
-.queuecommand = sun3scsi_queue_command, \
-.abort = sun3scsi_abort, \
-.reset = sun3scsi_reset, \
-.can_queue = CAN_QUEUE, /* can queue */ \
-.this_id = 7, /* id */ \
-.sg_tablesize = SG_TABLESIZE, /* sg_tablesize */ \
-.cmd_per_lun = CMD_PER_LUN, /* cmd per lun */ \
-.unchecked_isa_dma = 0, /* unchecked_isa_dma */ \
-.use_clustering = DISABLE_CLUSTERING \
- }
-
#ifndef HOSTS_C
#define NCR5380_implementation_fields \
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index f6f2b810f577..056a65cd4551 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -387,10 +387,9 @@ void sun3_sun3_debug (void)
NCR5380_local_declare();
if (default_instance) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
NCR5380_print_status(default_instance);
- restore_flags(flags);
+ local_irq_restore(flags);
}
}
#endif
@@ -561,7 +560,21 @@ static int sun3scsi_dma_finish(int write_flag)
#include "sun3_NCR5380.c"
-static Scsi_Host_Template driver_template = SUN3_NCR5380;
+static Scsi_Host_Template driver_template = {
+ .name = SUN3_SCSI_NAME,
+ .detect = sun3scsi_detect,
+ .release = sun3scsi_release,
+ .info = sun3scsi_info,
+ .queuecommand = sun3scsi_queue_command,
+ .abort = sun3scsi_abort,
+ .reset = sun3scsi_reset,
+ .can_queue = CAN_QUEUE,
+ .this_id = 7,
+ .sg_tablesize = SG_TABLESIZE,
+ .cmd_per_lun = CMD_PER_LUN,
+ .use_clustering = DISABLE_CLUSTERING
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 76607c5e190a..bfbdf74c018b 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -13,12 +13,12 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
-#include "sun3x_esp.h"
#include <asm/sun3x.h>
#include <asm/dvma.h>
#include <asm/irq.h>
@@ -374,7 +374,23 @@ static void dma_advance_sg (Scsi_Cmnd *sp)
sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
}
-static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP;
+static Scsi_Host_Template driver_template = {
+ .proc_name = "esp",
+ .proc_info = &esp_proc_info,
+ .name = "Sun ESP 100/100a/200",
+ .detect = sun3x_esp_detect,
+ .info = esp_info,
+ .command = esp_command,
+ .queuecommand = esp_queue,
+ .eh_abort_handler = esp_abort,
+ .eh_bus_reset_handler = esp_reset,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+};
+
#include "scsi_module.c"
diff --git a/drivers/scsi/sun3x_esp.h b/drivers/scsi/sun3x_esp.h
deleted file mode 100644
index 653a775ef185..000000000000
--- a/drivers/scsi/sun3x_esp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* sun3x_esp.h: Defines and structures for the Sun3x ESP
- *
- * (C) 1995 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- */
-
-#ifndef _SUN3X_ESP_H
-#define _SUN3X_ESP_H
-
-/* For dvma controller register definitions. */
-#include <asm/dvma.h>
-
-extern int sun3x_esp_detect(struct SHT *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *, unsigned int);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout);
-
-#define DMA_PORTS_P (dregs->cond_reg & DMA_INT_ENAB)
-
-#define SCSI_SUN3X_ESP { \
- .proc_name = "esp", \
- .proc_info = &esp_proc_info, \
- .name = "Sun ESP 100/100a/200", \
- .detect = sun3x_esp_detect, \
- .info = esp_info, \
- .command = esp_command, \
- .queuecommand = esp_queue, \
- .abort = esp_abort, \
- .reset = esp_reset, \
- .can_queue = 7, \
- .this_id = 7, \
- .sg_tablesize = SG_ALL, \
- .cmd_per_lun = 1, \
- .use_clustering = DISABLE_CLUSTERING, }
-
-#endif /* !(_SUN3X_ESP_H) */
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 4ce9a4a76ec0..37bb9c87e677 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -315,7 +315,6 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
struct WD33C93_hostdata *hostdata;
Scsi_Cmnd *tmp;
- unsigned long flags;
hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
@@ -385,8 +384,7 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
* sense data is not lost before REQUEST_SENSE executes.
*/
- save_flags(flags);
- cli();
+ spin_lock_irq(&hostdata->lock);
if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
cmd->host_scribble = (uchar *)hostdata->input_Q;
@@ -407,7 +405,7 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
- restore_flags(flags);
+ spin_unlock_irq(&hostdata->lock);
return 0;
}
@@ -765,7 +763,7 @@ unsigned long length, flags;
if (!(asr & ASR_INT) || (asr & ASR_BSY))
return;
- save_flags(flags);
+ spin_lock_irqsave(&hostdata->lock, flags);
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
@@ -831,7 +829,7 @@ DB(DB_INTR,printk("TIMEOUT"))
* is here...
*/
- restore_flags(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
/* We are not connected to a target - check to see if there
* are commands waiting to be executed.
@@ -885,7 +883,8 @@ printk(" sending SDTR ");
hostdata->outgoing_len = 1;
hostdata->state = S_CONNECTED;
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_XFER_DONE|PHS_DATA_IN:
@@ -895,7 +894,8 @@ DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
transfer_bytes(regs, cmd, DATA_IN_DIR);
if (hostdata->state != S_RUNNING_LEVEL2)
hostdata->state = S_CONNECTED;
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_XFER_DONE|PHS_DATA_OUT:
@@ -905,7 +905,8 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
transfer_bytes(regs, cmd, DATA_OUT_DIR);
if (hostdata->state != S_RUNNING_LEVEL2)
hostdata->state = S_CONNECTED;
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
/* Note: this interrupt should not occur in a LEVEL2 command */
@@ -916,7 +917,8 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
hostdata->state = S_CONNECTED;
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_XFER_DONE|PHS_STATUS:
@@ -935,7 +937,8 @@ DB(DB_INTR,printk("%02x",cmd->SCp.Status))
else {
hostdata->state = S_CONNECTED;
}
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_XFER_DONE|PHS_MESS_IN:
@@ -1085,7 +1088,7 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
break;
@@ -1117,12 +1120,13 @@ DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
- restore_flags(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
wd33c93_execute(instance);
}
else {
printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid);
- }
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ }
break;
@@ -1133,7 +1137,8 @@ DB(DB_INTR,printk("SDP"))
hostdata->state = S_RUNNING_LEVEL2;
write_wd33c93(regs, WD_COMMAND_PHASE, 0x41);
write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_XFER_DONE|PHS_MESS_OUT:
@@ -1163,7 +1168,8 @@ DB(DB_INTR,printk("MSG_OUT="))
DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
hostdata->outgoing_len = 0;
hostdata->state = S_CONNECTED;
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
case CSR_UNEXP_DISC:
@@ -1184,7 +1190,8 @@ DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
- return;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ return;
}
DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
hostdata->connected = NULL;
@@ -1200,7 +1207,7 @@ DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
* there are commands waiting to be executed.
*/
/* look above for comments on scsi_done() */
- restore_flags(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
wd33c93_execute(instance);
break;
@@ -1228,7 +1235,6 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status))
else
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
cmd->scsi_done(cmd);
- restore_flags(flags);
break;
case S_PRE_TMP_DISC:
case S_RUNNING_LEVEL2:
@@ -1250,6 +1256,7 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status))
/* We are no longer connected to a target - check to see if
* there are commands waiting to be executed.
*/
+ spin_unlock_irqrestore(&hostdata->lock, flags);
wd33c93_execute(instance);
break;
@@ -1367,7 +1374,8 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
if (!cmd) {
printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun);
- return;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ return;
}
/* Ok, found the command - now start it up again. */
@@ -1397,10 +1405,12 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
hostdata->state = S_CONNECTED;
DB(DB_INTR,printk("-%ld",cmd->pid))
- break;
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ break;
default:
printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
}
DB(DB_INTR,printk("} "))
@@ -1830,12 +1840,9 @@ char buf[32];
#endif
- { unsigned long flags;
- save_flags(flags);
- cli();
- reset_wd33c93(instance);
- restore_flags(flags);
- }
+ spin_lock_irq(&hostdata->lock);
+ reset_wd33c93(instance);
+ spin_unlock_irq(&hostdata->lock);
printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",instance->host_no,
(hostdata->chip==C_WD33C93)?"WD33c93":
@@ -1863,7 +1870,6 @@ int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int i
char *bp;
char tbuf[128];
-unsigned long flags;
struct Scsi_Host *instance;
struct WD33C93_hostdata *hd;
Scsi_Cmnd *cmd;
@@ -1928,8 +1934,7 @@ static int stop = 0;
return len;
}
- save_flags(flags);
- cli();
+ spin_lock_irq(&hd->lock);
bp = buf;
*bp = '\0';
if (hd->proc & PR_VERSION) {
@@ -2004,7 +2009,7 @@ static int stop = 0;
}
}
strcat(bp,"\n");
- restore_flags(flags);
+ spin_unlock_irq(&hd->lock);
*start = buf;
if (stop) {
stop = 0;
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 7d55ed8bd47f..47fd46fc4022 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -217,6 +217,7 @@ struct sx_period {
struct WD33C93_hostdata {
struct Scsi_Host *next;
wd33c93_regs regs;
+ spinlock_t lock;
uchar clock_freq;
uchar chip; /* what kind of wd33c93? */
uchar microcode; /* microcode rev */
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index d9767337fe1f..7faee8111c81 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -48,7 +48,7 @@ obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_CLGEN) += clgenfb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
-obj-$(CONFIG_FB_TGA) += tgafb.o
+obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
@@ -76,7 +76,6 @@ obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o
obj-$(CONFIG_FB_SUN3) += sun3fb.o
-obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index fd55dbcabf6f..1ef989cd66be 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -57,6 +57,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -2050,8 +2051,7 @@ static void st_ovsc_switch(void)
if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
return;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
mfp.tim_ct_b = 0x10;
mfp.active_edge |= 8;
@@ -2079,7 +2079,7 @@ static void st_ovsc_switch(void)
((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* ------------------- External Video ---------------------- */
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 43c030ff9ad7..f99a1692d5cb 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -38,7 +38,7 @@
#define BYTES_PER_LONG 4
#else
#define FB_WRITEL fb_writeq
-#define FB_READL fb_readq(x)
+#define FB_READL fb_readq
#define SHIFT_PER_LONG 6
#define BYTES_PER_LONG 8
#endif
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 11a87a694a85..f47b173b383e 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -21,13 +21,13 @@
*
* FIXME
* The code for 24 bit is horrible. It copies byte by byte size instead of
- * longs like the other sizes. Needs to be optimized.
+ * words like the other sizes. Needs to be optimized.
*
* Tony:
* Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
* up the code significantly.
*
- * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
+ * Code for depths not multiples of BITS_PER_WORD is still kludgy, which is
* still processed a bit at a time.
*
* Also need to add code to deal with cards endians that are different than
@@ -48,7 +48,11 @@
#define DPRINTK(fmt, args...)
#endif
-static u32 cfb_tab8[] = {
+/* The following code can *not* handle a 64-bit long. */
+#define WORD u32
+#define BITS_PER_WORD 32
+
+static WORD const cfb_tab8[] = {
#if defined(__BIG_ENDIAN)
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
@@ -64,7 +68,7 @@ static u32 cfb_tab8[] = {
#endif
};
-static u32 cfb_tab16[] = {
+static WORD const cfb_tab16[] = {
#if defined(__BIG_ENDIAN)
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
#elif defined(__LITTLE_ENDIAN)
@@ -74,11 +78,11 @@ static u32 cfb_tab16[] = {
#endif
};
-static u32 cfb_tab32[] = {
+static WORD const cfb_tab32[] = {
0x00000000, 0xffffffff
};
-#if BITS_PER_LONG == 32
+#if BITS_PER_WORD == 32
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
#else
@@ -87,7 +91,7 @@ static u32 cfb_tab32[] = {
#endif
#if defined (__BIG_ENDIAN)
-#define LEFT_POS(bpp) (BITS_PER_LONG - bpp)
+#define LEFT_POS(bpp) (BITS_PER_WORD - bpp)
#define NEXT_POS(pos, bpp) ((pos) -= (bpp))
#define SHIFT_HIGH(val, bits) ((val) >> (bits))
#define SHIFT_LOW(val, bits) ((val) << (bits))
@@ -99,25 +103,25 @@ static u32 cfb_tab32[] = {
#endif
static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
- unsigned long start_index, unsigned long pitch_index)
+ WORD start_index, WORD pitch_index)
{
/* Draw the penguin */
int i, n;
- unsigned long bitmask = SHIFT_LOW(~0UL, BITS_PER_LONG - p->var.bits_per_pixel);
- unsigned long *palette = (unsigned long *) p->pseudo_palette;
- unsigned long *dst, *dst2, color = 0, val, shift;
- unsigned long null_bits = BITS_PER_LONG - p->var.bits_per_pixel;
+ WORD bitmask = SHIFT_LOW(~0UL, BITS_PER_WORD - p->var.bits_per_pixel);
+ u32 *palette = (u32 *) p->pseudo_palette;
+ WORD *dst, *dst2, color = 0, val, shift;
+ WORD null_bits = BITS_PER_WORD - p->var.bits_per_pixel;
u8 *src = image->data;
- dst2 = (unsigned long *) dst1;
+ dst2 = (WORD *) dst1;
for (i = image->height; i--; ) {
n = image->width;
- dst = (unsigned long *) dst1;
+ dst = (WORD *) dst1;
shift = 0;
val = 0;
if (start_index) {
- unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index));
+ WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index));
val = FB_READL(dst) & start_mask;
shift = start_index;
@@ -134,14 +138,14 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
if (shift == null_bits)
val = 0;
else
- val = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ val = SHIFT_LOW(color, BITS_PER_WORD - shift);
}
shift += p->var.bits_per_pixel;
- shift &= (BITS_PER_LONG - 1);
+ shift &= (BITS_PER_WORD - 1);
src++;
}
if (shift) {
- unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+ WORD end_mask = SHIFT_HIGH(~0UL, shift);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
@@ -149,35 +153,35 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
if (pitch_index) {
dst2 += p->fix.line_length;
dst1 = (char *) dst2;
- (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+ (size_t) dst1 &= ~(sizeof(WORD) - 1);
start_index += pitch_index;
- start_index &= BITS_PER_LONG - 1;
+ start_index &= BITS_PER_WORD - 1;
}
}
}
static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
- unsigned long fgcolor, unsigned long bgcolor,
- unsigned long start_index, unsigned long pitch_index)
+ WORD fgcolor, WORD bgcolor,
+ WORD start_index, WORD pitch_index)
{
- unsigned long i, j, l = 8;
- unsigned long shift, color, bpp = p->var.bits_per_pixel;
- unsigned long *dst, *dst2, val, pitch = p->fix.line_length;
- unsigned long null_bits = BITS_PER_LONG - bpp;
+ WORD i, j, l = 8;
+ WORD shift, color, bpp = p->var.bits_per_pixel;
+ WORD *dst, *dst2, val, pitch = p->fix.line_length;
+ WORD null_bits = BITS_PER_WORD - bpp;
u8 *src = image->data;
- dst2 = (unsigned long *) dst1;
+ dst2 = (WORD *) dst1;
for (i = image->height; i--; ) {
shift = 0;
val = 0;
j = image->width;
- dst = (unsigned long *) dst1;
+ dst = (WORD *) dst1;
/* write leading bits */
if (start_index) {
- unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index));
+ WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index));
val = FB_READL(dst) & start_mask;
shift = start_index;
@@ -196,15 +200,15 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8
if (shift == null_bits)
val = 0;
else
- val = SHIFT_LOW(color, BITS_PER_LONG - shift);
+ val = SHIFT_LOW(color, BITS_PER_WORD - shift);
}
shift += bpp;
- shift &= (BITS_PER_LONG - 1);
+ shift &= (BITS_PER_WORD - 1);
if (!l) { l = 8; src++; };
}
/* write trailing bits */
if (shift) {
- unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+ WORD end_mask = SHIFT_HIGH(~0UL, shift);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
@@ -213,24 +217,24 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8
if (pitch_index) {
dst2 += pitch;
dst1 = (char *) dst2;
- (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+ (size_t) dst1 &= ~(sizeof(WORD) - 1);
start_index += pitch_index;
- start_index &= BITS_PER_LONG - 1;
+ start_index &= BITS_PER_WORD - 1;
}
}
}
static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1,
- unsigned long fgcolor, unsigned long bgcolor)
+ WORD fgcolor, WORD bgcolor)
{
int i, j, k, l = 8, n;
- unsigned long bit_mask, end_mask, eorx;
- unsigned long fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel;
- unsigned long tmp = (1 << bpp) - 1;
- unsigned long ppw = BITS_PER_LONG/bpp, ppos;
- unsigned long *dst;
+ WORD bit_mask, end_mask, eorx;
+ WORD fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel;
+ WORD tmp = (1 << bpp) - 1;
+ WORD ppw = BITS_PER_WORD/bpp, ppos;
+ WORD *dst;
u32 *tab = NULL;
char *src = image->data;
@@ -263,7 +267,7 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8
k = image->width/ppw;
for (i = image->height; i--; ) {
- dst = (unsigned long *) dst1;
+ dst = (WORD *) dst1;
for (j = k; j--; ) {
l -= ppw;
@@ -291,8 +295,8 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8
void cfb_imageblit(struct fb_info *p, struct fb_image *image)
{
int x2, y2, vxres, vyres;
- unsigned long fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
- unsigned long bpl = sizeof(unsigned long), bpp = p->var.bits_per_pixel;
+ WORD fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+ WORD bpl = sizeof(WORD), bpp = p->var.bits_per_pixel;
u8 *dst1;
vxres = p->var.xres_virtual;
@@ -315,7 +319,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image)
image->height = y2 - image->dy;
bitstart = (image->dy * p->fix.line_length * 8) + (image->dx * bpp);
- start_index = bitstart & (BITS_PER_LONG - 1);
+ start_index = bitstart & (BITS_PER_WORD - 1);
pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
bitstart /= 8;
@@ -332,7 +336,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image)
bgcolor = image->bg_color;
}
- if (BITS_PER_LONG % bpp == 0 && !start_index && !pitch_index &&
+ if (BITS_PER_WORD % bpp == 0 && !start_index && !pitch_index &&
bpp >= 8 && bpp <= 32 && (image->width & 7) == 0)
fast_imageblit(image, p, dst1, fgcolor, bgcolor);
else
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6b3bc39bc559..57cd3ca0a32d 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -75,6 +75,7 @@
#include <linux/selection.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/system.h>
diff --git a/drivers/video/console/font.h b/drivers/video/console/font.h
index d612657374d0..16564d51d28e 100644
--- a/drivers/video/console/font.h
+++ b/drivers/video/console/font.h
@@ -8,18 +8,10 @@
* for more details.
*/
-#ifndef _VIDEO_FONT_H
-#define _VIDEO_FONT_H
+#ifndef _VIDEO_CONSOLE_FONT_H
+#define _VIDEO_CONSOLE_FONT_H
-#include <linux/types.h>
-
-struct font_desc {
- int idx;
- char *name;
- int width, height;
- void *data;
- int pref;
-};
+#include <video/font.h> /* struct font_desc */
#define VGA8x8_IDX 0
#define VGA8x16_IDX 1
@@ -50,4 +42,4 @@ extern struct font_desc *get_default_font(int xres, int yres);
/* Max. length for the name of a predefined font */
#define MAX_FONT_NAME 32
-#endif /* _VIDEO_FONT_H */
+#endif /* _VIDEO_CONSOLE_FONT_H */
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 325f0ab1ae6c..230f0c971e66 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -1,1009 +1,725 @@
/*
* linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
*
- * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
- *
- * $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $
- *
- * This driver is partly based on the original TGA framebuffer device, which
- * was partly based on the original TGA console driver, which are
- *
- * Copyright (C) 1997 Geert Uytterhoeven
* Copyright (C) 1995 Jay Estabrook
+ * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
+ * Copyright (C) 2002 Richard Henderson
*
* 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.
*/
-/* KNOWN PROBLEMS/TO DO ===================================================== *
- *
- * - How to set a single color register on 24-plane cards?
- *
- * - Hardware cursor/other text acceleration methods
- *
- * - Some redraws can stall kernel for several seconds
- * [This should now be solved by the fast memmove() patch in 2.3.6]
- *
- * KNOWN PROBLEMS/TO DO ==================================================== */
-
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/fb.h>
#include <linux/selection.h>
-#include <linux/console.h>
+#include <linux/pci.h>
#include <asm/io.h>
+#include <video/tgafb.h>
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb32.h>
-#include "tgafb.h"
-
-
- /*
- * Global declarations
- */
-
-static struct tgafb_info fb_info;
-static struct tgafb_par current_par;
-static int current_par_valid = 0;
-static struct display disp;
-static char default_fontname[40] __initdata = { 0 };
-static struct fb_var_screeninfo default_var;
-static int default_var_valid = 0;
+/*
+ * Local functions.
+ */
-static struct { u_char red, green, blue, pad; } palette[256];
-#ifdef FBCON_HAS_CFB32
-static u32 fbcon_cfb32_cmap[16];
+static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int tgafb_set_par(struct fb_info *);
+static void tgafb_set_pll(struct tga_par *, int);
+static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned,
+ unsigned, struct fb_info *);
+static int tgafb_blank(int, struct fb_info *);
+static void tgafb_init_fix(struct fb_info *);
+static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);
+#ifdef MODULE
+static void tgafb_pci_unregister(struct pci_dev *);
#endif
+static const char *mode_option = "640x480@60";
- /*
- * Hardware presets
- */
-static unsigned int fb_offset_presets[4] = {
- TGA_8PLANE_FB_OFFSET,
- TGA_24PLANE_FB_OFFSET,
- 0xffffffff,
- TGA_24PLUSZ_FB_OFFSET
-};
+/*
+ * Frame buffer operations
+ */
-static unsigned int deep_presets[4] = {
- 0x00014000,
- 0x0001440d,
- 0xffffffff,
- 0x0001441d
+static struct fb_ops tgafb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = tgafb_check_var,
+ .fb_set_par = tgafb_set_par,
+ .fb_setcolreg = tgafb_setcolreg,
+ .fb_blank = tgafb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = soft_cursor,
};
-static unsigned int rasterop_presets[4] = {
- 0x00000003,
- 0x00000303,
- 0xffffffff,
- 0x00000303
-};
-static unsigned int mode_presets[4] = {
- 0x00002000,
- 0x00002300,
- 0xffffffff,
- 0x00002300
-};
+/*
+ * PCI registration operations
+ */
-static unsigned int base_addr_presets[4] = {
- 0x00000000,
- 0x00000001,
- 0xffffffff,
- 0x00000001
+static struct pci_device_id const tgafb_pci_table[] = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 0 }
};
-
- /*
- * Predefined video modes
- * This is a subset of the standard VESA modes, recalculated from XFree86.
- *
- * XXX Should we store these in terms of the encoded par structs? Even better,
- * fbcon should provide a general mechanism for doing something like this.
- */
-
-static struct {
- const char *name;
- struct fb_var_screeninfo var;
-} tgafb_predefined[] __initdata = {
- { "640x480-60", {
- 640, 480, 640, 480, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "800x600-56", {
- 800, 600, 800, 600, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 27777, 128, 24, 22, 1, 72, 2,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "640x480-72", {
- 640, 480, 640, 480, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 31746, 144, 40, 30, 8, 40, 3,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "800x600-60", {
- 800, 600, 800, 600, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "800x600-72", {
- 800, 600, 800, 600, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20000, 64, 56, 23, 37, 120, 6,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "1024x768-60", {
- 1024, 768, 1024, 768, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 15384, 168, 8, 29, 3, 144, 6,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1152x864-60", {
- 1152, 864, 1152, 864, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 11123, 208, 64, 16, 4, 256, 8,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1024x768-70", {
- 1024, 768, 1024, 768, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13333, 144, 24, 29, 3, 136, 6,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1024x768-76", {
- 1024, 768, 1024, 768, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 11764, 208, 8, 36, 16, 120, 3,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1152x864-70", {
- 1152, 864, 1152, 864, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 10869, 106, 56, 20, 1, 160, 10,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1280x1024-61", {
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 9090, 200, 48, 26, 1, 184, 3,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1024x768-85", {
- 1024, 768, 1024, 768, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 10111, 192, 32, 34, 14, 160, 6,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1280x1024-70", {
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 7905, 224, 32, 28, 8, 160, 8,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1152x864-84", {
- 1152, 864, 1152, 864, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 184, 312, 32, 0, 128, 12,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1280x1024-76", {
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 248, 32, 34, 3, 104, 3,
- 0,
- FB_VMODE_NONINTERLACED
- }},
- { "1280x1024-85", {
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 6349, 224, 64, 44, 1, 160, 3,
- 0,
- FB_VMODE_NONINTERLACED
- }},
-
- /* These are modes used by the two fixed-frequency monitors I have at home.
- * You may or may not find these useful.
- */
-
- { "WYSE1", { /* 1280x1024 @ 72 Hz, 130 Mhz clock */
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 192, 32, 47, 0, 192, 5,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "IBM3", { /* 1280x1024 @ 70 Hz, 120 Mhz clock */
- 1280, 1024, 1280, 1024, 0, 0, 0, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 8333, 192, 32, 47, 0, 192, 5,
- 0,
- FB_VMODE_NONINTERLACED
- }}
+static struct pci_driver tgafb_driver = {
+ .name = "tgafb",
+ .id_table = tgafb_pci_table,
+ .probe = tgafb_pci_register,
+ .remove = __devexit_p(tgafb_pci_unregister),
};
-#define NUM_TOTAL_MODES ARRAY_SIZE(tgafb_predefined)
-
-
- /*
- * Interface used by the world
- */
-
-static void tgafb_detect(void);
-static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
- struct fb_info_gen *info);
-static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
- struct fb_info_gen *info);
-static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
- struct fb_info_gen *info);
-static void tgafb_get_par(void *fb_par, struct fb_info_gen *info);
-static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info);
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int tgafb_blank(int blank, struct fb_info_gen *info);
-static void tgafb_set_disp(const void *fb_par, struct display *disp,
- struct fb_info_gen *info);
-
-#ifndef MODULE
-int tgafb_setup(char*);
-#endif
-
-static void tgafb_set_pll(int f);
-#if 1
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static void tgafb_update_palette(void);
-#endif
-
-
- /*
- * Chipset specific functions
- */
-
-static void tgafb_detect(void)
+/**
+ * tgafb_check_var - Optional function. Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- return;
-}
+ struct tga_par *par = (struct tga_par *)info->par;
+
+ if (par->tga_type == TGA_TYPE_8PLANE) {
+ if (var->bits_per_pixel > 8)
+ return -EINVAL;
+ } else {
+ if (var->bits_per_pixel > 32)
+ return -EINVAL;
+ }
+ if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+ return -EINVAL;
+ if (var->nonstd)
+ return -EINVAL;
+ if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
+ return -EINVAL;
+ if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
-static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
- struct fb_info_gen *info)
-{
- struct tgafb_par *par = (struct tgafb_par *)fb_par;
-
- strcpy(fix->id, fb_info.gen.info.modename);
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (fb_info.tga_type == TGA_TYPE_8PLANE) {
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- } else {
- fix->visual = FB_VISUAL_TRUECOLOR;
- }
-
- fix->line_length = par->xres * (par->bits_per_pixel >> 3);
- fix->smem_start = fb_info.tga_fb_base;
- fix->smem_len = fix->line_length * par->yres;
- fix->mmio_start = fb_info.tga_regs_base;
- fix->mmio_len = 0x1000; /* Is this sufficient? */
- fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0;
- fix->accel = FB_ACCEL_DEC_TGA;
-
- return 0;
+ return 0;
}
-
-static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
- struct fb_info_gen *info)
+/**
+ * tgafb_set_par - Optional function. Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_set_par(struct fb_info *info)
{
- struct tgafb_par *par = (struct tgafb_par *)fb_par;
+ static unsigned int const deep_presets[4] = {
+ 0x00014000,
+ 0x0001440d,
+ 0xffffffff,
+ 0x0001441d
+ };
+ static unsigned int const rasterop_presets[4] = {
+ 0x00000003,
+ 0x00000303,
+ 0xffffffff,
+ 0x00000303
+ };
+ static unsigned int const mode_presets[4] = {
+ 0x00002000,
+ 0x00002300,
+ 0xffffffff,
+ 0x00002300
+ };
+ static unsigned int const base_addr_presets[4] = {
+ 0x00000000,
+ 0x00000001,
+ 0xffffffff,
+ 0x00000001
+ };
+
+ struct tga_par *par = (struct tga_par *) info->par;
+ u32 htimings, vtimings, pll_freq;
+ u8 tga_type;
+ int i, j;
+
+ /* Encode video timings. */
+ htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB)
+ | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB));
+ vtimings = (info->var.yres & TGA_VERT_ACTIVE);
+ htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP;
+ vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP;
+ htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC;
+ vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC;
+ htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP;
+ vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP;
+
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ htimings |= TGA_HORIZ_POLARITY;
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ vtimings |= TGA_VERT_POLARITY;
+
+ par->htimings = htimings;
+ par->vtimings = vtimings;
+
+ par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN);
+
+ /* Store other useful values in par. */
+ par->xres = info->var.xres;
+ par->yres = info->var.yres;
+ par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
+ par->bits_per_pixel = info->var.bits_per_pixel;
+
+ tga_type = par->tga_type;
+
+ /* First, disable video. */
+ TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
+
+ /* Write the DEEP register. */
+ while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
+ continue;
+ mb();
+ TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG);
+ while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
+ continue;
+ mb();
+
+ /* Write some more registers. */
+ TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG);
+ TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG);
+ TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
+
+ /* Calculate & write the PLL. */
+ tgafb_set_pll(par, pll_freq);
+
+ /* Write some more registers. */
+ TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG);
+ TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG);
+ TGA_WRITE_REG(par, 0x12345678, TGA_BLOCK_COLOR0_REG);
+ TGA_WRITE_REG(par, 0x12345678, TGA_BLOCK_COLOR1_REG);
+
+ /* Init video timing regs. */
+ TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);
+ TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
+
+ /* Initalise RAMDAC. */
+ if (tga_type == TGA_TYPE_8PLANE) {
+
+ /* Init BT485 RAMDAC registers. */
+ BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
+ BT485_CMD_0);
+ BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE);
+ BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */
+ BT485_WRITE(par, 0x40, BT485_CMD_1);
+ BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */
+ BT485_WRITE(par, 0xff, BT485_PIXEL_MASK);
+
+ /* Fill palette registers. */
+ BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
+ TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+
+ for (i = 0; i < 16; i++) {
+ j = color_table[i];
+ TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ }
+ for (i = 0; i < 240*3; i += 4) {
+ TGA_WRITE_REG(par, 0x55|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_RAMDAC_REG);
+ }
+
+ } else { /* 24-plane or 24plusZ */
+
+ /* Init BT463 registers. */
+ BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2,
+ (par->sync_on_green ? 0x80 : 0x40));
+
+ BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f);
+
+ BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
+ BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
+
+ /* Fill the palette. */
+ BT463_LOAD_ADDR(par, 0x0000);
+ TGA_WRITE_REG(par, BT463_PALETTE<<2, TGA_RAMDAC_REG);
+
+ for (i = 0; i < 16; i++) {
+ j = color_table[i];
+ TGA_WRITE_REG(par, default_red[j]|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_grn[j]|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_blu[j]|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ }
+ for (i = 0; i < 512*3; i += 4) {
+ TGA_WRITE_REG(par, 0x55|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+ TGA_RAMDAC_REG);
+ }
+
+ /* Fill window type table after start of vertical retrace. */
+ while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
+ continue;
+ TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
+ mb();
+ while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
+ continue;
+ TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
+
+ BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE);
+ TGA_WRITE_REG(par, BT463_REG_ACC<<2, TGA_RAMDAC_SETUP_REG);
+
+ for (i = 0; i < 16; i++) {
+ TGA_WRITE_REG(par, 0x00|(BT463_REG_ACC<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x01|(BT463_REG_ACC<<10),
+ TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x80|(BT463_REG_ACC<<10),
+ TGA_RAMDAC_REG);
+ }
- /* round up some */
- if (fb_info.tga_type == TGA_TYPE_8PLANE) {
- if (var->bits_per_pixel > 8) {
- return -EINVAL;
- }
- par->bits_per_pixel = 8;
- } else {
- if (var->bits_per_pixel > 32) {
- return -EINVAL;
}
- par->bits_per_pixel = 32;
- }
-
- /* check the values for sanity */
- if (var->xres_virtual != var->xres ||
- var->yres_virtual != var->yres ||
- var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ ||
- (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED
-#if 0 /* fbmon not done. uncomment for 2.5.x -brad */
- || !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
-#else
- )
-#endif
- return -EINVAL;
-
- /* encode video timings */
- par->htimings = ((var->xres/4) & TGA_HORIZ_ACT_LSB) |
- (((var->xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB);
- par->vtimings = (var->yres & TGA_VERT_ACTIVE);
- par->htimings |= ((var->right_margin/4) << 9) & TGA_HORIZ_FP;
- par->vtimings |= (var->lower_margin << 11) & TGA_VERT_FP;
- par->htimings |= ((var->hsync_len/4) << 14) & TGA_HORIZ_SYNC;
- par->vtimings |= (var->vsync_len << 16) & TGA_VERT_SYNC;
- par->htimings |= ((var->left_margin/4) << 21) & TGA_HORIZ_BP;
- par->vtimings |= (var->upper_margin << 22) & TGA_VERT_BP;
-
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- par->htimings |= TGA_HORIZ_POLARITY;
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- par->vtimings |= TGA_VERT_POLARITY;
- if (var->sync & FB_SYNC_ON_GREEN) {
- par->sync_on_green = 1;
- } else {
- par->sync_on_green = 0;
- }
-
- /* store other useful values in par */
- par->xres = var->xres;
- par->yres = var->yres;
- par->pll_freq = 1000000000/var->pixclock;
- par->bits_per_pixel = var->bits_per_pixel;
-
- return 0;
-}
+ /* Finally, enable video scan (and pray for the monitor... :-) */
+ TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG);
-static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
- struct fb_info_gen *info)
-{
- struct tgafb_par *par = (struct tgafb_par *)fb_par;
-
- /* decode video timings */
- var->xres = ((par->htimings & TGA_HORIZ_ACT_LSB) | ((par->htimings & TGA_HORIZ_ACT_MSB) >> 19)) * 4;
- var->yres = (par->vtimings & TGA_VERT_ACTIVE);
- var->right_margin = ((par->htimings & TGA_HORIZ_FP) >> 9) * 4;
- var->lower_margin = ((par->vtimings & TGA_VERT_FP) >> 11);
- var->hsync_len = ((par->htimings & TGA_HORIZ_SYNC) >> 14) * 4;
- var->vsync_len = ((par->vtimings & TGA_VERT_SYNC) >> 16);
- var->left_margin = ((par->htimings & TGA_HORIZ_BP) >> 21) * 4;
- var->upper_margin = ((par->vtimings & TGA_VERT_BP) >> 22);
-
- if (par->htimings & TGA_HORIZ_POLARITY)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (par->vtimings & TGA_VERT_POLARITY)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
- if (par->sync_on_green == 1)
- var->sync |= FB_SYNC_ON_GREEN;
-
- var->xres_virtual = var->xres;
- var->yres_virtual = var->yres;
- var->xoffset = var->yoffset = 0;
-
- /* depth-related */
- if (fb_info.tga_type == TGA_TYPE_8PLANE) {
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- } else {
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- }
- var->bits_per_pixel = par->bits_per_pixel;
- var->grayscale = 0;
- var->red.length = var->green.length = var->blue.length = 8;
- var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
- var->transp.offset = var->transp.length = var->transp.msb_right = 0;
-
- /* others */
- var->xoffset = var->yoffset = 0;
- var->pixclock = 1000000000/par->pll_freq;
- var->nonstd = 0;
- var->activate = 0;
- var->height = var->width = -1;
- var->accel_flags = 0;
-
- return 0;
+ return 0;
}
-
-static void tgafb_get_par(void *fb_par, struct fb_info_gen *info)
+#define DIFFCHECK(X) \
+do { \
+ if (m <= 0x3f) { \
+ int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \
+ if (delta < 0) \
+ delta = -delta; \
+ if (delta < min_diff) \
+ min_diff = delta, vm = m, va = a, vr = r; \
+ } \
+} while (0)
+
+static void
+tgafb_set_pll(struct tga_par *par, int f)
{
- struct tgafb_par *par = (struct tgafb_par *)fb_par;
+ int n, shift, base, min_diff, target;
+ int r,a,m,vm = 34, va = 1, vr = 30;
+
+ for (r = 0 ; r < 12 ; r++)
+ TGA_WRITE_REG(par, !r, TGA_CLOCK_REG);
- if (current_par_valid)
- *par = current_par;
- else {
- if (fb_info.tga_type == TGA_TYPE_8PLANE)
- default_var.bits_per_pixel = 8;
+ if (f > TGA_PLL_MAX_FREQ)
+ f = TGA_PLL_MAX_FREQ;
+
+ if (f >= TGA_PLL_MAX_FREQ / 2)
+ shift = 0;
+ else if (f >= TGA_PLL_MAX_FREQ / 4)
+ shift = 1;
else
- default_var.bits_per_pixel = 32;
+ shift = 2;
- tgafb_decode_var(&default_var, par, info);
- }
-}
+ TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG);
+ for (r = 0 ; r < 10 ; r++)
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
-static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info)
-{
- int i, j;
- struct tgafb_par *par = (struct tgafb_par *)fb_par;
-
-#if 0
- /* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */
- /* if current_par is valid, check to see if we need to change anything */
- if (current_par_valid) {
- if (!memcmp(par, &current_par, sizeof current_par)) {
- return;
+ if (f <= 120000) {
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
}
- }
-#endif
- current_par = *par;
- current_par_valid = 1;
-
- /* first, disable video */
- TGA_WRITE_REG(TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
-
- /* write the DEEP register */
- while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
- continue;
-
- mb();
- TGA_WRITE_REG(deep_presets[fb_info.tga_type], TGA_DEEP_REG);
- while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
- continue;
- mb();
-
- /* write some more registers */
- TGA_WRITE_REG(rasterop_presets[fb_info.tga_type], TGA_RASTEROP_REG);
- TGA_WRITE_REG(mode_presets[fb_info.tga_type], TGA_MODE_REG);
- TGA_WRITE_REG(base_addr_presets[fb_info.tga_type], TGA_BASE_ADDR_REG);
-
- /* calculate & write the PLL */
- tgafb_set_pll(par->pll_freq);
-
- /* write some more registers */
- TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG);
- TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG);
- TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG);
- TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG);
-
- /* init video timing regs */
- TGA_WRITE_REG(par->htimings, TGA_HORIZ_REG);
- TGA_WRITE_REG(par->vtimings, TGA_VERT_REG);
-
- /* initalise RAMDAC */
- if (fb_info.tga_type == TGA_TYPE_8PLANE) {
-
- /* init BT485 RAMDAC registers */
- BT485_WRITE(0xa2 | (par->sync_on_green ? 0x8 : 0x0), BT485_CMD_0);
- BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE);
- BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */
- BT485_WRITE(0x40, BT485_CMD_1);
- BT485_WRITE(0x20, BT485_CMD_2); /* cursor off, for now */
- BT485_WRITE(0xff, BT485_PIXEL_MASK);
-
- /* fill palette registers */
- BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
- TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- palette[i].red=default_red[j];
- palette[i].green=default_grn[j];
- palette[i].blue=default_blu[j];
+ else if (f <= 200000) {
+ TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
}
- for (i = 0; i < 240*3; i += 4) {
- TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- }
-
- } else { /* 24-plane or 24plusZ */
-
- /* init BT463 registers */
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2,
- (par->sync_on_green ? 0x80 : 0x40));
-
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_2, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_3, 0x0f);
-
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
-
- /* fill the palette */
- BT463_LOAD_ADDR(0x0000);
- TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+ else {
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
}
- for (i = 0; i < 512*3; i += 4) {
- TGA_WRITE_REG(0x55|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- }
-
- /* fill window type table after start of vertical retrace */
- while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01))
- continue;
- TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG);
- mb();
- while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01))
- continue;
- TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG);
-
- BT463_LOAD_ADDR(BT463_WINDOW_TYPE_BASE);
- TGA_WRITE_REG((BT463_REG_ACC<<2), TGA_RAMDAC_SETUP_REG);
-
- for (i = 0; i < 16; i++) {
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
+
+ TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+
+ target = (f << shift) / TGA_PLL_BASE_FREQ;
+ min_diff = TGA_PLL_MAX_FREQ;
+
+ r = 7 / target;
+ if (!r) r = 1;
+
+ base = target * r;
+ while (base < 449) {
+ for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) {
+ m = ((n + 3) / 7) - 1;
+ a = 0;
+ DIFFCHECK((m + 1) * 7);
+ m++;
+ DIFFCHECK((m + 1) * 7);
+ m = (n / 6) - 1;
+ if ((a = n % 6))
+ DIFFCHECK(n);
+ }
+ r++;
+ base += target;
}
-
- }
- /* finally, enable video scan
- (and pray for the monitor... :-) */
- TGA_WRITE_REG(TGA_VALID_VIDEO, TGA_VALID_REG);
-}
+ vr--;
+ for (r = 0; r < 8; r++)
+ TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG);
+ for (r = 0; r < 8 ; r++)
+ TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG);
+ for (r = 0; r < 7 ; r++)
+ TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG);
+ TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG);
+}
-#define DIFFCHECK(x) { if( m <= 0x3f ) { \
- int delta = f - (TGA_PLL_BASE_FREQ * (x)) / (r << shift); \
- if (delta < 0) delta = -delta; \
- if (delta < min_diff) min_diff = delta, vm = m, va = a, vr = r; } }
-static void tgafb_set_pll(int f)
+/**
+ * tgafb_setcolreg - Optional function. Sets a color register.
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ */
+static int
+tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
{
- int n, shift, base, min_diff, target;
- int r,a,m,vm = 34, va = 1, vr = 30;
-
- for( r = 0 ; r < 12 ; r++ )
- TGA_WRITE_REG(!r, TGA_CLOCK_REG);
-
- if (f > TGA_PLL_MAX_FREQ)
- f = TGA_PLL_MAX_FREQ;
-
- if (f >= TGA_PLL_MAX_FREQ / 2)
- shift = 0;
- else if (f >= TGA_PLL_MAX_FREQ / 4)
- shift = 1;
- else
- shift = 2;
-
- TGA_WRITE_REG(shift & 1, TGA_CLOCK_REG);
- TGA_WRITE_REG(shift >> 1, TGA_CLOCK_REG);
-
- for( r = 0 ; r < 10 ; r++ ) {
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- }
-
- if (f <= 120000) {
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- }
- else if (f <= 200000) {
- TGA_WRITE_REG(1, TGA_CLOCK_REG);
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- }
- else {
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- TGA_WRITE_REG(1, TGA_CLOCK_REG);
- }
-
- TGA_WRITE_REG(1, TGA_CLOCK_REG);
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- TGA_WRITE_REG(1, TGA_CLOCK_REG);
- TGA_WRITE_REG(0, TGA_CLOCK_REG);
- TGA_WRITE_REG(1, TGA_CLOCK_REG);
-
- target = (f << shift) / TGA_PLL_BASE_FREQ;
- min_diff = TGA_PLL_MAX_FREQ;
-
- r = 7 / target;
- if (!r)
- r = 1;
-
- base = target * r;
- while (base < 449) {
- for (n = base < 7 ? 7 : base ; n < base + target && n < 449; n++) {
- m = ((n + 3) / 7) - 1;
- a = 0;
- DIFFCHECK((m + 1) * 7);
- m++;
- DIFFCHECK((m + 1) * 7);
- m = (n / 6) - 1;
- if( (a = n % 6))
- DIFFCHECK( n );
+ struct tga_par *par = (struct tga_par *) info->par;
+
+ if (regno > 255)
+ return 1;
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ if (par->tga_type == TGA_TYPE_8PLANE) {
+ BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
+ TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+ } else if (regno < 16) {
+ u32 value = (red << 16) | (green << 8) | blue;
+ ((u32 *)info->pseudo_palette)[regno] = value;
}
- r++;
- base += target;
- }
-
- vr--;
-
- for( r=0; r<8 ; r++) {
- TGA_WRITE_REG((vm >> r) & 1, TGA_CLOCK_REG);
- }
- for( r=0; r<8 ; r++) {
- TGA_WRITE_REG((va >> r) & 1, TGA_CLOCK_REG);
- }
- for( r=0; r<7 ; r++) {
- TGA_WRITE_REG((vr >> r) & 1, TGA_CLOCK_REG);
- }
- TGA_WRITE_REG(((vr >> 7) & 1)|2, TGA_CLOCK_REG);
-}
-
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- if (regno > 255)
- return 1;
- *red = (palette[regno].red<<8) | palette[regno].red;
- *green = (palette[regno].green<<8) | palette[regno].green;
- *blue = (palette[regno].blue<<8) | palette[regno].blue;
- *transp = 0;
- return 0;
+ return 0;
}
-static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
+/**
+ * tgafb_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_blank(int blank, struct fb_info *info)
{
- if (regno > 255)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
-
-#ifdef FBCON_HAS_CFB32
- if (regno < 16 && fb_info.tga_type != TGA_TYPE_8PLANE)
- fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
-#endif
-
- if (fb_info.tga_type == TGA_TYPE_8PLANE) {
- BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
- TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
- TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- }
- /* How to set a single color register on 24-plane cards?? */
+ struct tga_par *par = (struct tga_par *) info->par;
+ u32 vhcr, vvcr, vvvr;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ vhcr = TGA_READ_REG(par, TGA_HORIZ_REG);
+ vvcr = TGA_READ_REG(par, TGA_VERT_REG);
+ vvvr = TGA_READ_REG(par, TGA_VALID_REG);
+ vvvr &= ~(TGA_VALID_VIDEO | TGA_VALID_BLANK);
+
+ switch (blank) {
+ case 0: /* Unblanking */
+ if (par->vesa_blanked) {
+ TGA_WRITE_REG(par, vhcr & 0xbfffffff, TGA_HORIZ_REG);
+ TGA_WRITE_REG(par, vvcr & 0xbfffffff, TGA_VERT_REG);
+ par->vesa_blanked = 0;
+ }
+ TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO, TGA_VALID_REG);
+ break;
+
+ case 1: /* Normal blanking */
+ TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK,
+ TGA_VALID_REG);
+ break;
+
+ case 2: /* VESA blank (vsync off) */
+ TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
+ TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+ par->vesa_blanked = 1;
+ break;
+
+ case 3: /* VESA blank (hsync off) */
+ TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
+ TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+ par->vesa_blanked = 1;
+ break;
+
+ case 4: /* Poweroff */
+ TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
+ TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
+ TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+ par->vesa_blanked = 1;
+ break;
+ }
- return 0;
+ local_irq_restore(flags);
+ return 0;
}
-#if 1
- /*
- * FIXME: since I don't know how to set a single arbitrary color register
- * on 24-plane cards, all color palette registers have to be updated
- */
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
-
- if (!fb_display[con].cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0)))
- return err;
- }
- if (con == info->currcon) { /* current console? */
- err = fb_set_cmap(cmap, kspc, info);
-#if 1
- if (fb_info.tga_type != TGA_TYPE_8PLANE)
- tgafb_update_palette();
-#endif
- return err;
- } else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
-}
+/*
+ * Initialisation
+ */
-static void tgafb_update_palette(void)
+static void
+tgafb_init_fix(struct fb_info *info)
{
- int i;
+ struct tga_par *par = (struct tga_par *)info->par;
+ u8 tga_type = par->tga_type;
+ const char *tga_type_name;
- BT463_LOAD_ADDR(0x0000);
- TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
-
- for (i = 0; i < 256; i++) {
- TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- }
-}
-#endif
+ switch (tga_type) {
+ case TGA_TYPE_8PLANE:
+ tga_type_name = "Digital ZLXp-E1";
+ break;
+ case TGA_TYPE_24PLANE:
+ tga_type_name = "Digital ZLXp-E2";
+ break;
+ case TGA_TYPE_24PLUSZ:
+ tga_type_name = "Digital ZLXp-E3";
+ break;
+ default:
+ tga_type_name = "Unknown";
+ break;
+ }
+ strncpy(info->fix.id, tga_type_name, sizeof(info->fix.id) - 1);
+ info->fix.id[sizeof(info->fix.id)-1] = 0;
-static int tgafb_blank(int blank, struct fb_info_gen *info)
-{
- static int tga_vesa_blanked = 0;
- u32 vhcr, vvcr, vvvr;
- unsigned long flags;
-
- local_irq_save(flags);
-
- vhcr = TGA_READ_REG(TGA_HORIZ_REG);
- vvcr = TGA_READ_REG(TGA_VERT_REG);
- vvvr = TGA_READ_REG(TGA_VALID_REG) & ~(TGA_VALID_VIDEO | TGA_VALID_BLANK);
-
- switch (blank) {
- case 0: /* Unblanking */
- if (tga_vesa_blanked) {
- TGA_WRITE_REG(vhcr & 0xbfffffff, TGA_HORIZ_REG);
- TGA_WRITE_REG(vvcr & 0xbfffffff, TGA_VERT_REG);
- tga_vesa_blanked = 0;
- }
- TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO, TGA_VALID_REG);
- break;
-
- case 1: /* Normal blanking */
- TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
- break;
-
- case 2: /* VESA blank (vsync off) */
- TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG);
- TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
- tga_vesa_blanked = 1;
- break;
-
- case 3: /* VESA blank (hsync off) */
- TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG);
- TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
- tga_vesa_blanked = 1;
- break;
-
- case 4: /* Poweroff */
- TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG);
- TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG);
- TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
- tga_vesa_blanked = 1;
- break;
- }
-
- local_irq_restore(flags);
- return 0;
-}
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.visual = (tga_type == TGA_TYPE_8PLANE
+ ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_TRUECOLOR);
+ info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
+ info->fix.smem_start = (size_t) par->tga_fb_base;
+ info->fix.smem_len = info->fix.line_length * par->yres;
+ info->fix.mmio_start = (size_t) par->tga_regs_base;
+ info->fix.mmio_len = 0x1000; /* Is this sufficient? */
-static void tgafb_set_disp(const void *fb_par, struct display *disp,
- struct fb_info_gen *info)
-{
- switch (fb_info.tga_type) {
-#ifdef FBCON_HAS_CFB8
- case TGA_TYPE_8PLANE:
- disp->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case TGA_TYPE_24PLANE:
- case TGA_TYPE_24PLUSZ:
- disp->dispsw = &fbcon_cfb32;
- disp->dispsw_data = &fbcon_cfb32_cmap;
- break;
-#endif
- default:
- disp->dispsw = &fbcon_dummy;
- }
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
- disp->scrollmode = SCROLL_YREDRAW;
+ info->fix.accel = FB_ACCEL_DEC_TGA;
}
+static __devinit int
+tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static unsigned int const fb_offset_presets[4] = {
+ TGA_8PLANE_FB_OFFSET,
+ TGA_24PLANE_FB_OFFSET,
+ 0xffffffff,
+ TGA_24PLUSZ_FB_OFFSET
+ };
+
+ struct all_info {
+ struct fb_info info;
+ struct tga_par par;
+ u32 pseudo_palette[16];
+ } *all;
+
+ void *mem_base;
+ unsigned long bar0_start, bar0_len;
+ u8 tga_type;
+ int ret;
+
+ /* Enable device in PCI config. */
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
+ return -ENODEV;
+ }
-struct fbgen_hwswitch tgafb_hwswitch = {
- tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par,
- tgafb_set_par, tgafb_getcolreg, NULL, tgafb_blank,
- tgafb_set_disp
-};
-
+ /* Allocate the fb and par structures. */
+ all = kmalloc(sizeof(*all), GFP_KERNEL);
+ if (!all) {
+ printk(KERN_ERR "tgafb: Cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(all, 0, sizeof(*all));
+ pci_set_drvdata(pdev, all);
+
+ /* Request the mem regions. */
+ bar0_start = pci_resource_start(pdev, 0);
+ bar0_len = pci_resource_len(pdev, 0);
+ ret = -ENODEV;
+ if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
+ printk(KERN_ERR "tgafb: cannot reserve FB region\n");
+ goto err0;
+ }
- /*
- * Hardware Independent functions
- */
+ /* Map the framebuffer. */
+ mem_base = ioremap(bar0_start, bar0_len);
+ if (!mem_base) {
+ printk(KERN_ERR "tgafb: Cannot map MMIO\n");
+ goto err1;
+ }
+ /* Grab info about the card. */
+ tga_type = (readl(mem_base) >> 12) & 0x0f;
+ all->par.pdev = pdev;
+ all->par.tga_mem_base = mem_base;
+ all->par.tga_fb_base = mem_base + fb_offset_presets[tga_type];
+ all->par.tga_regs_base = mem_base + TGA_REGS_OFFSET;
+ all->par.tga_type = tga_type;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &all->par.tga_chip_rev);
+
+ /* Setup framebuffer. */
+ all->info.node = NODEV;
+ all->info.flags = FBINFO_FLAG_DEFAULT;
+ all->info.fbops = &tgafb_ops;
+ all->info.screen_base = (char *) all->par.tga_fb_base;
+ all->info.currcon = -1;
+ all->info.par = &all->par;
+ all->info.pseudo_palette = all->pseudo_palette;
+
+ /* This should give a reasonable default video mode. */
+
+ ret = fb_find_mode(&all->info.var, &all->info, mode_option,
+ NULL, 0, NULL,
+ tga_type == TGA_TYPE_8PLANE ? 8 : 32);
+ if (ret == 0 || ret == 4) {
+ printk(KERN_ERR "tgafb: Could not find valid video mode\n");
+ ret = -EINVAL;
+ goto err1;
+ }
- /*
- * Frame buffer operations
- */
+ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+ printk(KERN_ERR "tgafb: Could not allocate color map\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
-static struct fb_ops tgafb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = fbgen_get_fix,
- .fb_get_var = fbgen_get_var,
- .fb_set_var = fbgen_set_var,
- .fb_get_cmap = fbgen_get_cmap,
- .fb_set_cmap = tgafb_set_cmap,
- .fb_setcolreg = tgafb_setcolreg,
- .fb_blank = fbgen_blank,
-};
+ tgafb_set_par(&all->info);
+ tgafb_init_fix(&all->info);
+ if (register_framebuffer(&all->info) < 0) {
+ printk(KERN_ERR "tgafb: Could not register framebuffer\n");
+ ret = -EINVAL;
+ goto err1;
+ }
-#ifndef MODULE
- /*
- * Setup
- */
-
-int __init tgafb_setup(char *options) {
- char *this_opt;
- int i;
-
- if (options && *options) {
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) { continue; }
-
- if (!strncmp(this_opt, "font:", 5)) {
- strncpy(default_fontname, this_opt+5, sizeof default_fontname);
- }
-
- else if (!strncmp(this_opt, "mode:", 5)) {
- for (i = 0; i < NUM_TOTAL_MODES; i++) {
- if (!strcmp(this_opt+5, tgafb_predefined[i].name))
- default_var = tgafb_predefined[i].var;
- default_var_valid = 1;
- }
- }
-
- else {
- printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt);
- }
- }
- }
- return 0;
+ printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
+ all->par.tga_chip_rev);
+ printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
+ minor(all->info.node), all->info.fix.id, bar0_start);
+
+ return 0;
+
+ err1:
+ release_mem_region(bar0_start, bar0_len);
+ err0:
+ kfree(all);
+ return ret;
}
-#endif
-
- /*
- * Initialisation
- */
-
-int __init tgafb_init(void)
+int __init
+tgafb_init(void)
{
- struct pci_dev *pdev;
-
- pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
- if (!pdev)
- return -ENXIO;
-
- /* divine board type */
-
- fb_info.tga_mem_base = (unsigned long)ioremap(pdev->resource[0].start, 0);
- fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f;
- fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET;
- fb_info.tga_fb_base = (fb_info.tga_mem_base
- + fb_offset_presets[fb_info.tga_type]);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &fb_info.tga_chip_rev);
-
- /* setup framebuffer */
-
- fb_info.gen.info.node = NODEV;
- fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
- fb_info.gen.info.fbops = &tgafb_ops;
- fb_info.gen.info.screen_base = (char *)fb_info.tga_fb_base;
- fb_info.gen.info.disp = &disp;
- fb_info.gen.info.currcon = -1;
- fb_info.gen.info.changevar = NULL;
- fb_info.gen.info.switch_con = &fbgen_switch;
- fb_info.gen.info.updatevar = &fbgen_update_var;
- strcpy(fb_info.gen.info.fontname, default_fontname);
- fb_info.gen.parsize = sizeof (struct tgafb_par);
- fb_info.gen.fbhw = &tgafb_hwswitch;
- fb_info.gen.fbhw->detect();
-
- printk (KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", fb_info.tga_chip_rev);
- printk (KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
- pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-
- switch (fb_info.tga_type)
- {
- case TGA_TYPE_8PLANE:
- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E1");
- break;
-
- case TGA_TYPE_24PLANE:
- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E2");
- break;
-
- case TGA_TYPE_24PLUSZ:
- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E3");
- break;
- }
-
- /* This should give a reasonable default video mode */
-
- if (!default_var_valid) {
- default_var = tgafb_predefined[0].var;
- }
- fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
- disp.var.activate = FB_ACTIVATE_NOW;
- fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
- fbgen_set_disp(-1, &fb_info.gen);
- do_install_cmap(0, &fb_info.gen);
- if (register_framebuffer(&fb_info.gen.info) < 0)
- return -EINVAL;
- printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
- minor(fb_info.gen.info.node), fb_info.gen.info.modename,
- pdev->resource[0].start);
- return 0;
+ return pci_module_init(&tgafb_driver);
}
+#ifdef MODULE
+static void __exit
+tgafb_pci_unregister(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct tga_par *par = info->par;
+
+ if (!info)
+ return;
+ unregister_framebuffer(info);
+ iounmap(par->tga_mem_base);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ kfree(info);
+}
- /*
- * Cleanup
- */
-
-void __exit tgafb_cleanup(void)
+static void __exit
+tgafb_exit(void)
{
- unregister_framebuffer(&fb_info.gen.info);
+ pci_unregister_driver(&tgafb_driver);
}
+#endif /* MODULE */
+#ifndef MODULE
+int __init
+tgafb_setup(char *arg)
+{
+ char *this_opt;
+
+ if (arg && *arg) {
+ while ((this_opt = strsep(&arg, ","))) {
+ if (!*this_opt)
+ continue;
+ if (!strncmp(this_opt, "mode:", 5))
+ mode_option = this_opt+5;
+ else
+ printk(KERN_ERR
+ "tgafb: unknown parameter %s\n",
+ this_opt);
+ }
+ }
- /*
- * Modularisation
- */
+ return 0;
+}
+#endif /* !MODULE */
+
+/*
+ * Modularisation
+ */
#ifdef MODULE
-MODULE_LICENSE("GPL");
module_init(tgafb_init);
+module_exit(tgafb_exit);
#endif
-module_exit(tgafb_cleanup);
+MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index f236e21749ab..5410e84760e6 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -193,6 +193,11 @@ static void __init check_config(void)
&& (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
#endif
+
+#ifdef CONFIG_X86_SSE2
+ if (!cpu_has_sse2)
+ panic("Kernel compiled for SSE2, CPU doesn't have it.");
+#endif
}
static void __init check_bugs(void)
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index 92ff7f79dee4..5f019713fa4c 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -75,6 +75,7 @@
#define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC)
#define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE)
#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
+#define cpu_has_sse2 boot_cpu_has(X86_FEATURE_XMM2)
#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
#define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP)
#define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR)
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 9de3a8a9bf58..01cdbdc7a32b 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -489,7 +489,7 @@ static inline void rep_nop(void)
#define cpu_relax() rep_nop()
/* Prefetch instructions for Pentium III and AMD Athlon */
-#ifdef CONFIG_MPENTIUMIII
+#ifdef CONFIG_X86_PREFETCH
#define ARCH_HAS_PREFETCH
extern inline void prefetch(const void *x)
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index fc8f116430bc..e085e51e9d25 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -288,9 +288,13 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
* nop for these.
*/
+#ifdef CONFIG_X86_SSE2
+#define mb() asm volatile("mfence" ::: "memory")
+#define rmb() asm volatile("lfence" ::: "memory")
+#else
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
#define rmb() mb()
-
+#endif
/**
* read_barrier_depends - Flush all pending reads that subsequents reads
* depend on.
diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h
index 1471687982a9..6b451e47441c 100644
--- a/include/asm-m68k/ide.h
+++ b/include/asm-m68k/ide.h
@@ -147,26 +147,28 @@ static __inline__ void ide_init_default_hwifs(void)
#ifdef CONFIG_ATARI
#define ATA_ARCH_LOCK
-static __inline__ void ide_release_lock (int *ide_lock)
+extern int ide_intr_lock;
+
+static __inline__ void ide_release_lock (void)
{
if (MACH_IS_ATARI) {
- if (*ide_lock == 0) {
+ if (ide_intr_lock == 0) {
printk("ide_release_lock: bug\n");
return;
}
- *ide_lock = 0;
+ ide_intr_lock = 0;
stdma_release();
}
}
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+static __inline__ void ide_get_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
{
if (MACH_IS_ATARI) {
- if (*ide_lock == 0) {
+ if (ide_intr_lock == 0) {
if (in_interrupt() > 0)
panic( "Falcon IDE hasn't ST-DMA lock in interrupt" );
stdma_lock(handler, data);
- *ide_lock = 1;
+ ide_intr_lock = 1;
}
}
}
diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h
index 47ad33cc2254..cbb1cb10cf73 100644
--- a/include/asm-m68k/macintosh.h
+++ b/include/asm-m68k/macintosh.h
@@ -76,9 +76,9 @@ struct mac_model
#define MAC_IDE_BABOON 3
#define MAC_SCC_II 1
-#define MAC_SCC_QUADRA 2
-#define MAC_SCC_QUADRA2 3
-#define MAC_SCC_IOP 4
+#define MAC_SCC_IOP 2
+#define MAC_SCC_QUADRA 3
+#define MAC_SCC_PSC 4
#define MAC_ETHER_NONE 0
#define MAC_ETHER_SONIC 1
@@ -139,6 +139,7 @@ struct mac_model
#define MAC_MODEL_P475F 90 /* aka: P475 w/ FPU (no LC040) */
#define MAC_MODEL_P575 92 /* aka: LC575, P577/P578 */
#define MAC_MODEL_Q605 94
+#define MAC_MODEL_Q605_ACC 95 /* Q605 accelerated to 33 MHz */
#define MAC_MODEL_Q630 98 /* aka: LC630, P630/631/635/636/637/638/640 */
#define MAC_MODEL_P588 99 /* aka: LC580, P580 */
#define MAC_MODEL_PB280 102
diff --git a/include/asm-m68k/mman.h b/include/asm-m68k/mman.h
index a171fb7c7acf..59c2d3c265d1 100644
--- a/include/asm-m68k/mman.h
+++ b/include/asm-m68k/mman.h
@@ -18,6 +18,8 @@
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define MAP_LOCKED 0x2000 /* pages are locked */
#define MAP_NORESERVE 0x4000 /* don't check for reservations */
+#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x10000 /* do not block on IO */
#define MS_ASYNC 1 /* sync memory asynchronously */
#define MS_INVALIDATE 2 /* invalidate the caches */
diff --git a/include/asm-m68k/module.h b/include/asm-m68k/module.h
index a978a053c89f..c6d75af2d8d3 100644
--- a/include/asm-m68k/module.h
+++ b/include/asm-m68k/module.h
@@ -1,12 +1,7 @@
#ifndef _ASM_M68K_MODULE_H
#define _ASM_M68K_MODULE_H
-/*
- * This file contains the m68k architecture specific module code.
- */
-
-#define module_map(x) vmalloc(x)
-#define module_unmap(x) vfree(x)
-#define module_arch_init(x) (0)
-#define arch_init_modules(x) do { } while (0)
-
+struct mod_arch_specific { };
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
#endif /* _ASM_M68K_MODULE_H */
diff --git a/include/asm-m68k/sbus.h b/include/asm-m68k/sbus.h
index ed76953cafb1..5dd2fac1b9ce 100644
--- a/include/asm-m68k/sbus.h
+++ b/include/asm-m68k/sbus.h
@@ -5,7 +5,7 @@
#ifndef __M68K_SBUS_H
#define __M68K_SBUS_H
-struct linux_sbus_device {
+struct sbus_dev {
struct {
unsigned int which_io;
unsigned int phys_addr;
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index 8fe94c6017fd..112ea2a6a047 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -74,12 +74,14 @@ static inline int irqs_disabled(void)
#define mb() barrier()
#define rmb() barrier()
#define wmb() barrier()
+#define read_barrier_depends() do { } while(0)
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
+#define smp_read_barrier_depends() do { } while(0)
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index 55244ef06d37..49988674166f 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -10,6 +10,7 @@ struct thread_info {
struct exec_domain *exec_domain; /* execution domain */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */
__u32 cpu; /* should always be 0 on m68k */
+ struct restart_block restart_block;
__u8 supervisor_stack[0];
};
@@ -20,6 +21,9 @@ struct thread_info {
{ \
.task = &tsk, \
.exec_domain = &default_exec_domain, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
}
/* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */
diff --git a/include/asm-um/a.out.h b/include/asm-um/a.out.h
index 2e208223f860..7c26265e1d7a 100644
--- a/include/asm-um/a.out.h
+++ b/include/asm-um/a.out.h
@@ -1,7 +1,9 @@
#ifndef __UM_A_OUT_H
#define __UM_A_OUT_H
+#include "linux/config.h"
#include "asm/arch/a.out.h"
+#include "choose-mode.h"
#undef STACK_TOP
@@ -9,10 +11,10 @@ extern unsigned long stacksizelim;
extern unsigned long host_task_size;
-extern int honeypot;
-
#define STACK_ROOM (stacksizelim)
-#define STACK_TOP (honeypot ? host_task_size : task_size)
+extern int honeypot;
+#define STACK_TOP \
+ CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
#endif
diff --git a/include/asm-um/checksum.h b/include/asm-um/checksum.h
index 4b38f37c822e..5b501361e361 100644
--- a/include/asm-um/checksum.h
+++ b/include/asm-um/checksum.h
@@ -1,6 +1,6 @@
#ifndef __UM_CHECKSUM_H
#define __UM_CHECKSUM_H
-#include "asm/arch/checksum.h"
+#include "sysdep/checksum.h"
#endif
diff --git a/include/asm-um/mmu.h b/include/asm-um/mmu.h
index d276d24f07df..2cf35c21d694 100644
--- a/include/asm-um/mmu.h
+++ b/include/asm-um/mmu.h
@@ -1,6 +1,22 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __MMU_H
#define __MMU_H
-#include "asm/arch/mmu.h"
+#include "um_mmu.h"
#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 56ef77e1c1c8..e735fe0a95a9 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -1,20 +1,33 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_MMU_CONTEXT_H
#define __UM_MMU_CONTEXT_H
#include "linux/sched.h"
+#include "choose-mode.h"
-#define init_new_context(task, mm) (0)
#define get_mmu_context(task) do ; while(0)
#define activate_context(tsk) do ; while(0)
-#define destroy_context(mm) do ; while(0)
static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
{
}
+extern void switch_mm_skas(int mm_fd);
+
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ if(prev != next){
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+ if(next != &init_mm)
+ CHOOSE_MODE((void) 0,
+ switch_mm_skas(next->context.skas.mm_fd));
+ }
}
static inline void enter_lazy_tlb(struct mm_struct *mm,
@@ -22,4 +35,38 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
{
}
+extern int init_new_context_skas(struct task_struct *task,
+ struct mm_struct *mm);
+
+static inline int init_new_context_tt(struct task_struct *task,
+ struct mm_struct *mm)
+{
+ return(0);
+}
+
+static inline int init_new_context(struct task_struct *task,
+ struct mm_struct *mm)
+{
+ return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas,
+ task, mm));
+}
+
+extern void destroy_context_skas(struct mm_struct *mm);
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+ CHOOSE_MODE((void) 0, destroy_context_skas(mm));
+}
+
#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index e3279d1d0b31..f4c0f7eb0d05 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -18,6 +18,8 @@ struct page;
#undef PAGE_OFFSET
#undef KERNELBASE
+extern unsigned long uml_physmem;
+
#define PAGE_OFFSET (uml_physmem)
#define KERNELBASE PAGE_OFFSET
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index a79a756c3989..8d607c87418d 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -373,15 +373,15 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
}
/* Find an entry in the third-level page table.. */
-#define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address))
#define pte_offset_map(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address))
#define pte_offset_map_nested(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address))
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic((pte), KM_PTE0)
+#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G)
typedef u32 pte_addr_t;
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
index 7e771b8ca7db..435380cc08d7 100644
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -12,9 +12,9 @@ struct task_struct;
#include "linux/config.h"
#include "linux/signal.h"
-#include "asm/segment.h"
#include "asm/ptrace.h"
#include "asm/siginfo.h"
+#include "choose-mode.h"
struct mm_struct;
@@ -22,9 +22,24 @@ struct mm_struct;
#define cpu_relax() do ; while (0)
-struct thread_struct {
+#ifdef CONFIG_MODE_TT
+struct proc_tt_mode {
int extern_pid;
int tracing;
+ int switch_pipe[2];
+ int singlestep_syscall;
+ int vm_seq;
+};
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+struct proc_skas_mode {
+ void *switch_buf;
+ void *fork_buf;
+};
+#endif
+
+struct thread_struct {
int forking;
unsigned long kernel_stack;
int nsyscalls;
@@ -33,13 +48,18 @@ struct thread_struct {
int err;
void *fault_addr;
void *fault_catcher;
- int vm_seq;
struct task_struct *prev_sched;
unsigned long temp_stack;
- int switch_pipe[2];
- void *jmp;
+ void *exec_buf;
struct arch_thread arch;
- int singlestep_syscall;
+ union {
+#ifdef CONFIG_MODE_TT
+ struct proc_tt_mode tt;
+#endif
+#ifdef CONFIG_MODE_SKAS
+ struct proc_skas_mode skas;
+#endif
+ } mode;
struct {
int op;
union {
@@ -60,8 +80,6 @@ struct thread_struct {
#define INIT_THREAD \
{ \
- extern_pid: -1, \
- tracing: 0, \
forking: 0, \
kernel_stack: 0, \
nsyscalls: 0, \
@@ -69,13 +87,10 @@ struct thread_struct {
cr2: 0, \
err: 0, \
fault_addr: NULL, \
- vm_seq: 0, \
prev_sched: NULL, \
temp_stack: 0, \
- switch_pipe: { -1, -1 }, \
- jmp: NULL, \
+ exec_buf: NULL, \
arch: INIT_ARCH_THREAD, \
- singlestep_syscall: 0, \
request: { 0 } \
}
diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
index 18f6b5991856..0a5f77de79ba 100644
--- a/include/asm-um/ptrace-generic.h
+++ b/include/asm-um/ptrace-generic.h
@@ -8,6 +8,8 @@
#ifndef __ASSEMBLY__
+#include "linux/config.h"
+#include "skas_ptrace.h"
#include "asm/current.h"
#define pt_regs pt_regs_subarch
diff --git a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h
index 24d97e5fcf20..80b24a31b5fe 100644
--- a/include/asm-um/system-generic.h
+++ b/include/asm-um/system-generic.h
@@ -17,6 +17,7 @@
extern void *switch_to(void *prev, void *next, void *last);
+extern int get_signals(void);
extern int set_signals(int enable);
extern int get_signals(void);
extern void block_signals(void);
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 1cb0f45359f5..bd3f4fe40c6b 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -20,14 +20,9 @@ struct thread_info {
mm_segment_t addr_limit; /* thread address space:
0-0xBFFFFFFF for user
0-0xFFFFFFFF for kernel */
+ struct restart_block restart_block;
};
-/*
- * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-
#define INIT_THREAD_INFO(tsk) \
{ \
task: &tsk, \
@@ -36,6 +31,9 @@ struct thread_info {
cpu: 0, \
preempt_count: 1, \
addr_limit: KERNEL_DS, \
+ restart_block: { \
+ fn: do_no_restart_syscall, \
+ }, \
}
#define init_thread_info (init_thread_union.thread_info)
diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
index a8a7dfb7e4c8..e1dfea108857 100644
--- a/include/asm-um/uaccess.h
+++ b/include/asm-um/uaccess.h
@@ -1,18 +1,11 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_UACCESS_H
#define __UM_UACCESS_H
-#include "linux/string.h"
-#include "linux/sched.h"
-#include "asm/processor.h"
-#include "asm/errno.h"
-#include "asm/current.h"
-#include "asm/a.out.h"
-
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -26,8 +19,6 @@
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define ABOVE_KMEM (16 * 1024 * 1024)
-
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(TASK_SIZE)
@@ -35,56 +26,12 @@
#define get_fs() (current_thread_info()->addr_limit)
#define set_fs(x) (current_thread_info()->addr_limit = (x))
-extern unsigned long end_vm;
-extern unsigned long uml_physmem;
-
-#define under_task_size(addr, size) \
- (((unsigned long) (addr) < TASK_SIZE) && \
- (((unsigned long) (addr) + (size)) < TASK_SIZE))
-
-#define is_stack(addr, size) \
- (((unsigned long) (addr) < STACK_TOP) && \
- ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
- (((unsigned long) (addr) + (size)) <= STACK_TOP))
-
#define segment_eq(a, b) ((a).seg == (b).seg)
-#define access_ok(type, addr, size) \
- ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
- (under_task_size(addr, size) || is_stack(addr, size))))
-
-static inline int verify_area(int type, const void * addr, unsigned long size)
-{
- return(access_ok(type, addr, size) ? 0 : -EFAULT);
-}
-
-extern unsigned long get_fault_addr(void);
-
-extern int __do_copy_from_user(void *to, const void *from, int n,
- void **fault_addr, void **fault_catcher);
-
-static inline int copy_from_user(void *to, const void *from, int n)
-{
- return(access_ok(VERIFY_READ, from, n) ?
- __do_copy_from_user(to, from, n,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : n);
-}
+#include "um_uaccess.h"
#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
-extern int __do_copy_to_user(void *to, const void *from, int n,
- void **fault_addr, void **fault_catcher);
-
-static inline int copy_to_user(void *to, const void *from, int n)
-{
- return(access_ok(VERIFY_WRITE, to, n) ?
- __do_copy_to_user(to, from, n,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : n);
-}
-
#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
#define __get_user(x, ptr) \
@@ -128,49 +75,6 @@ static inline int copy_to_user(void *to, const void *from, int n)
__put_user(x, private_ptr) : -EFAULT); \
})
-extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
- void **fault_addr, void **fault_catcher);
-
-static inline int strncpy_from_user(char *dst, const char *src, int count)
-{
- int n;
-
- if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT);
- n = __do_strncpy_from_user(dst, src, count,
- &current->thread.fault_addr,
- &current->thread.fault_catcher);
- if(n < 0) return(-EFAULT);
- return(n);
-}
-
-extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
- void **fault_catcher);
-
-static inline int __clear_user(void *mem, int len)
-{
- return(__do_clear_user(mem, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-static inline int clear_user(void *mem, int len)
-{
- return(access_ok(VERIFY_WRITE, mem, len) ?
- __do_clear_user(mem, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : len);
-}
-
-extern int __do_strnlen_user(const char *str, unsigned long n,
- void **fault_addr, void **fault_catcher);
-
-static inline int strnlen_user(void *str, int len)
-{
- return(__do_strnlen_user(str, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
struct exception_table_entry
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index 72e575a68a33..c98d3c64bba0 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -244,7 +244,7 @@ static __inline__ int constant_test_bit(int nr, const volatile void * addr)
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
-static __inline__ int variable_test_bit(int nr, volatile void * addr)
+static __inline__ int variable_test_bit(int nr, volatile const void * addr)
{
int oldbit;
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index f5775b7ddde5..724777a946f6 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -131,7 +131,7 @@ static inline void set_tss_desc(unsigned cpu, void *addr)
static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
{
- set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr,
+ set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (unsigned long)addr,
DESC_LDT, size);
}
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
deleted file mode 100644
index e7e16901f686..000000000000
--- a/include/asm-x86_64/dma-mapping.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/dma-mapping.h>
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 9d7d039d5222..bb096fb7ab06 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -168,9 +168,24 @@ static inline void x86_do_profile (struct pt_regs *regs)
struct notifier_block;
+#ifdef CONFIG_PROFILING
+
int register_profile_notifier(struct notifier_block * nb);
int unregister_profile_notifier(struct notifier_block * nb);
+#else
+
+static inline int register_profile_notifier(struct notifier_block * nb)
+{
+ return -ENOSYS;
+}
+
+static inline int unregister_profile_notifier(struct notifier_block * nb)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_PROFILING */
#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
if (IO_APIC_IRQ(i))
diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h
index f257195d1740..23d4d607a398 100644
--- a/include/asm-x86_64/ia32.h
+++ b/include/asm-x86_64/ia32.h
@@ -202,7 +202,7 @@ struct iovec32 {
int iov_len;
};
-#define IA32_PAGE_OFFSET 0xffff0000
+#define IA32_PAGE_OFFSET 0xffffe000
#define IA32_STACK_TOP IA32_PAGE_OFFSET
#endif /* !CONFIG_IA32_SUPPORT */
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 2975afd3f3e5..d5e3a3a81282 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -3,6 +3,7 @@
#include <linux/config.h>
#include <asm/types.h>
+#include <asm/mpspec.h>
/*
* Intel IO-APIC support for SMP and UP systems.
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 075a49ff9ba4..9c84b14139f2 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -256,7 +256,7 @@ static inline void clear_in_cr4 (unsigned long mask)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_32 0x40000000
+#define TASK_UNMAPPED_32 0xa0000000
#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3)
#define TASK_UNMAPPED_BASE \
(test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index a9f8d7e16ee6..9ca683849c42 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -42,6 +42,8 @@ extern void exception_table_check(void);
extern int acpi_boot_init(char *);
+extern int map_syscall32(struct mm_struct *mm, unsigned long address);
+
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define round_down(x,y) ((x) & ~((y)-1))
diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
index 52047a7e928b..b502884f490a 100644
--- a/include/asm-x86_64/spinlock.h
+++ b/include/asm-x86_64/spinlock.h
@@ -48,8 +48,8 @@ typedef struct {
"js 2f\n" \
LOCK_SECTION_START("") \
"2:\t" \
- "cmpb $0,%0\n\t" \
"rep;nop\n\t" \
+ "cmpb $0,%0\n\t" \
"jle 2b\n\t" \
"jmp 1b\n" \
LOCK_SECTION_END
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index f1281d48dc93..268865b34785 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -254,7 +254,12 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
*/
#define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory")
-#define wmb() asm volatile("sfence":::"memory")
+
+/* could use SFENCE here, but it would be only needed for unordered SSE
+ store instructions and we always do an explicit sfence with them currently.
+ the ordering of normal stores is serialized enough. Just make it a compile
+ barrier. */
+#define wmb() asm volatile("" ::: "memory")
#define read_barrier_depends() do {} while(0)
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 69cac4da715d..9f034cf938d1 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -100,6 +100,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_IA32 18 /* 32bit process */
@@ -107,6 +108,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
+#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index 3cb62ac5fb08..065eb4c8dafb 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -103,7 +103,8 @@ extern void __get_user_8(void);
/* Careful: we have to cast the result to the type of the pointer for sign reasons */
#define get_user(x,ptr) \
-({ long __ret_gu,__val_gu; \
+({ long __val_gu; \
+ int __ret_gu; \
switch(sizeof (*(ptr))) { \
case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \
case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \
@@ -138,7 +139,7 @@ extern void __put_user_bad(void);
#define __put_user_nocheck(x,ptr,size) \
({ \
- long __pu_err; \
+ int __pu_err; \
__put_user_size((x),(ptr),(size),__pu_err); \
__pu_err; \
})
@@ -146,7 +147,7 @@ extern void __put_user_bad(void);
#define __put_user_check(x,ptr,size) \
({ \
- long __pu_err = -EFAULT; \
+ int __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
__put_user_size((x),__pu_addr,(size),__pu_err); \
@@ -157,10 +158,10 @@ extern void __put_user_bad(void);
do { \
retval = 0; \
switch (size) { \
- case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \
- case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \
- case 4: __put_user_asm(x,ptr,retval,"l","k","ir"); break; \
- case 8: __put_user_asm(x,ptr,retval,"q","","ir"); break; \
+ case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
+ case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
+ case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\
+ case 8: __put_user_asm(x,ptr,retval,"q","","ir",-EFAULT); break;\
default: __put_user_bad(); \
} \
} while (0)
@@ -174,12 +175,12 @@ struct __large_struct { unsigned long buf[100]; };
* we do not write to any memory gcc knows about, so there are no
* aliasing issues.
*/
-#define __put_user_asm(x, addr, err, itype, rtype, ltype) \
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \
__asm__ __volatile__( \
"1: mov"itype" %"rtype"1,%2\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
- "3: movq %3,%0\n" \
+ "3: mov %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
@@ -187,32 +188,33 @@ struct __large_struct { unsigned long buf[100]; };
" .quad 1b,3b\n" \
".previous" \
: "=r"(err) \
- : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+ : ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
#define __get_user_nocheck(x,ptr,size) \
({ \
- long __gu_err, __gu_val; \
+ int __gu_err; \
+ long __gu_val; \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
-extern long __get_user_bad(void);
+extern int __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval) \
do { \
retval = 0; \
switch (size) { \
- case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \
- case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \
- case 4: __get_user_asm(x,ptr,retval,"l","k","=r"); break; \
- case 8: __get_user_asm(x,ptr,retval,"q","","=r"); break; \
+ case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\
+ case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\
+ case 4: __get_user_asm(x,ptr,retval,"l","k","=r",-EFAULT); break;\
+ case 8: __get_user_asm(x,ptr,retval,"q","","=r",-EFAULT); break;\
default: (x) = __get_user_bad(); \
} \
} while (0)
-#define __get_user_asm(x, addr, err, itype, rtype, ltype) \
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno) \
__asm__ __volatile__( \
"1: mov"itype" %2,%"rtype"1\n" \
"2:\n" \
@@ -226,23 +228,77 @@ do { \
" .quad 1b,3b\n" \
".previous" \
: "=r"(err), ltype (x) \
- : "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+ : "m"(__m(addr)), "i"(errno), "0"(err))
/*
* Copy To/From Userspace
- *
- * This relies on an optimized common worker function.
- *
- * Could do special inline versions for small constant copies, but avoid this
- * for now. It's not clear it is worth it.
*/
+/* Handles exceptions in both to and from, but doesn't do access_ok */
extern unsigned long copy_user_generic(void *to, const void *from, unsigned len);
extern unsigned long copy_to_user(void *to, const void *from, unsigned len);
extern unsigned long copy_from_user(void *to, const void *from, unsigned len);
-#define __copy_to_user copy_user_generic
-#define __copy_from_user copy_user_generic
+
+static inline int __copy_from_user(void *dst, void *src, unsigned size)
+{
+ if (!__builtin_constant_p(size))
+ return copy_user_generic(dst,src,size);
+ int ret = 0;
+ switch (size) {
+ case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1);
+ return ret;
+ case 2:__get_user_asm(*(u16*)dst,(u16*)src,ret,"w","w","=r",2);
+ return ret;
+ case 4:__get_user_asm(*(u32*)dst,(u32*)src,ret,"l","k","=r",4);
+ return ret;
+ case 8:__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",8);
+ return ret;
+ case 10:
+ __get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
+ if (ret) return ret;
+ __get_user_asm(*(u16*)(8+dst),(u16*)(8+src),ret,"w","w","=r",2);
+ return ret;
+ case 16:
+ __get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
+ if (ret) return ret;
+ __get_user_asm(*(u64*)(8+dst),(u64*)(8+src),ret,"q","","=r",8);
+ return ret;
+ default:
+ return copy_user_generic(dst,src,size);
+ }
+}
+
+static inline int __copy_to_user(void *dst, void *src, unsigned size)
+{
+ if (!__builtin_constant_p(size))
+ return copy_user_generic(dst,src,size);
+ int ret = 0;
+ switch (size) {
+ case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1);
+ return ret;
+ case 2:__put_user_asm(*(u16*)src,(u16*)dst,ret,"w","w","ir",2);
+ return ret;
+ case 4:__put_user_asm(*(u32*)src,(u32*)dst,ret,"l","k","ir",4);
+ return ret;
+ case 8:__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",8);
+ return ret;
+ case 10:
+ __put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",10);
+ if (ret) return ret;
+ asm("":::"memory");
+ __put_user_asm(4[(u16*)src],4+(u16*)dst,ret,"w","w","ir",2);
+ return ret;
+ case 16:
+ __put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",16);
+ if (ret) return ret;
+ asm("":::"memory");
+ __put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8);
+ return ret;
+ default:
+ return copy_user_generic(dst,src,size);
+ }
+}
long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count);
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 23dd4c02ddec..188da2f94589 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -424,9 +424,11 @@ struct fb_info {
#define fb_readb __raw_readb
#define fb_readw __raw_readw
#define fb_readl __raw_readl
+#define fb_readq __raw_readq
#define fb_writeb __raw_writeb
#define fb_writew __raw_writew
#define fb_writel __raw_writel
+#define fb_writeq __raw_writeq
#define fb_memset memset_io
#else
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 033e94a6d6e4..2e2718ebfd98 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -360,8 +360,8 @@ extern int ide_irq_lock;
/* Currently only Atari needs it */
#ifndef IDE_ARCH_LOCK
-# define ide_release_lock(lock) do {} while (0)
-# define ide_get_lock(lock, hdlr, data) do {} while (0)
+# define ide_release_lock() do {} while (0)
+# define ide_get_lock(hdlr, data) do {} while (0)
#endif /* IDE_ARCH_LOCK */
/*
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index a3fd37b33fdd..870e66a96286 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -28,18 +28,18 @@ enum nubus_category {
};
enum nubus_type_network {
- NUBUS_TYPE_ETHERNET = 0x0001,
- NUBUS_TYPE_RS232 = 0x0002
+ NUBUS_TYPE_ETHERNET = 0x0001,
+ NUBUS_TYPE_RS232 = 0x0002
};
enum nubus_type_display {
- NUBUS_TYPE_VIDEO = 0x0001
+ NUBUS_TYPE_VIDEO = 0x0001
};
enum nubus_type_cpu {
- NUBUS_TYPE_68020 = 0x0003,
- NUBUS_TYPE_68030 = 0x0004,
- NUBUS_TYPE_68040 = 0x0005
+ NUBUS_TYPE_68020 = 0x0003,
+ NUBUS_TYPE_68030 = 0x0004,
+ NUBUS_TYPE_68040 = 0x0005
};
/* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
@@ -80,22 +80,24 @@ enum nubus_type_cpu {
/* Add known DrSW values here */
enum nubus_drsw {
/* NUBUS_CAT_DISPLAY */
- NUBUS_DRSW_APPLE = 0x0001,
- NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+ NUBUS_DRSW_APPLE = 0x0001,
+ NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
/* NUBUS_CAT_NETWORK */
- NUBUS_DRSW_CABLETRON = 0x0001,
- NUBUS_DRSW_SONIC_LC = 0x0001,
- NUBUS_DRSW_KINETICS = 0x0103,
- NUBUS_DRSW_ASANTE = 0x0104,
- NUBUS_DRSW_DAYNA = 0x010b,
- NUBUS_DRSW_FARALLON = 0x010c,
- NUBUS_DRSW_APPLE_SN = 0x010f,
- NUBUS_DRSW_FOCUS = 0x011a,
- NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */
+ NUBUS_DRSW_CABLETRON = 0x0001,
+ NUBUS_DRSW_SONIC_LC = 0x0001,
+ NUBUS_DRSW_KINETICS = 0x0103,
+ NUBUS_DRSW_ASANTE = 0x0104,
+ NUBUS_DRSW_DAYNA = 0x010b,
+ NUBUS_DRSW_FARALLON = 0x010c,
+ NUBUS_DRSW_APPLE_SN = 0x010f,
+ NUBUS_DRSW_DAYNA2 = 0x0115,
+ NUBUS_DRSW_FOCUS = 0x011a,
+ NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */
+ NUBUS_DRSW_DAYNA_LC = 0x011e,
/* NUBUS_CAT_CPU */
- NUBUS_DRSW_NONE = 0x0000,
+ NUBUS_DRSW_NONE = 0x0000,
};
/* DrHW: Uniquely identifies the hardware interface to a board (or at
@@ -106,11 +108,13 @@ enum nubus_drsw {
enum nubus_drhw {
/* NUBUS_CAT_DISPLAY */
NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */
+ NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */
NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */
NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */
NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+ NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
- NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
+ NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */
/* NUBUS_CAT_NETWORK */
NUBUS_DRHW_INTERLAN = 0x0100,
@@ -119,6 +123,11 @@ enum nubus_drhw {
NUBUS_DRHW_CABLETRON = 0x0109,
NUBUS_DRHW_ASANTE_LC = 0x010f,
NUBUS_DRHW_SONIC = 0x0110,
+ NUBUS_DRHW_SONIC_NB = 0x0118,
+ NUBUS_DRHW_SONIC_LC = 0x0119,
+
+ /* NUBUS_CAT_COMMUNICATIONS */
+ NUBUS_DRHW_DOVEFAX = 0x0100,
};
/* Resource IDs: These are the identifiers for the various weird and
@@ -153,8 +162,8 @@ enum nubus_board_res_id {
NUBUS_RESID_SECONDINIT = 0x0026,
/* Not sure why Apple put these next two in here */
- NUBUS_RESID_VIDNAMES = 0x0041,
- NUBUS_RESID_VIDMODES = 0x007e
+ NUBUS_RESID_VIDNAMES = 0x0041,
+ NUBUS_RESID_VIDMODES = 0x007e
};
/* Fields within the vendor info directory */
diff --git a/include/video/font.h b/include/video/font.h
new file mode 100644
index 000000000000..fd332b3a7179
--- /dev/null
+++ b/include/video/font.h
@@ -0,0 +1,24 @@
+/*
+ * font.h -- `Soft' font definitions
+ *
+ * Created 1995 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _VIDEO_FONT_H
+#define _VIDEO_FONT_H
+
+#include <linux/types.h>
+
+struct font_desc {
+ int idx;
+ char *name;
+ int width, height;
+ void *data;
+ int pref;
+};
+
+#endif /* _VIDEO_FONT_H */
diff --git a/drivers/video/tgafb.h b/include/video/tgafb.h
index 748d53fbd313..fbfae108a525 100644
--- a/drivers/video/tgafb.h
+++ b/include/video/tgafb.h
@@ -13,17 +13,17 @@
#ifndef TGAFB_H
#define TGAFB_H
- /*
- * TGA hardware description (minimal)
- */
+/*
+ * TGA hardware description (minimal)
+ */
#define TGA_TYPE_8PLANE 0
#define TGA_TYPE_24PLANE 1
#define TGA_TYPE_24PLUSZ 3
- /*
- * Offsets within Memory Space
- */
+/*
+ * Offsets within Memory Space
+ */
#define TGA_ROM_OFFSET 0x0000000
#define TGA_REGS_OFFSET 0x0100000
@@ -52,9 +52,9 @@
#define TGA_CMD_STAT_REG 0x01f8
- /*
- * useful defines for managing the registers
- */
+/*
+ * Useful defines for managing the registers
+ */
#define TGA_HORIZ_ODD 0x80000000
#define TGA_HORIZ_POLARITY 0x40000000
@@ -77,17 +77,17 @@
#define TGA_VALID_CURSOR 0x04
- /*
- * useful defines for managing the ICS1562 PLL clock
- */
+/*
+ * Useful defines for managing the ICS1562 PLL clock
+ */
#define TGA_PLL_BASE_FREQ 14318 /* .18 */
#define TGA_PLL_MAX_FREQ 230000
- /*
- * useful defines for managing the BT485 on the 8-plane TGA
- */
+/*
+ * Useful defines for managing the BT485 on the 8-plane TGA
+ */
#define BT485_READ_BIT 0x01
#define BT485_WRITE_BIT 0x00
@@ -111,9 +111,9 @@
#define BT485_CUR_HIGH_Y 0x1e
- /*
- * useful defines for managing the BT463 on the 24-plane TGAs
- */
+/*
+ * Useful defines for managing the BT463 on the 24-plane TGAs
+ */
#define BT463_ADDR_LO 0x0
#define BT463_ADDR_HI 0x1
@@ -139,61 +139,72 @@
#define BT463_WINDOW_TYPE_BASE 0x0300
+/*
+ * The framebuffer driver private data.
+ */
- /*
- * Macros for reading/writing TGA and RAMDAC registers
- */
-
-#define TGA_WRITE_REG(v,r) \
- { writel((v), fb_info.tga_regs_base+(r)); mb(); }
-
-#define TGA_READ_REG(r) readl(fb_info.tga_regs_base+(r))
-
-#define BT485_WRITE(v,r) \
- TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
-
-#define BT463_LOAD_ADDR(a) \
- TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
- TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
-
-#define BT463_WRITE(m,a,v) \
- BT463_LOAD_ADDR((a)); \
- TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
-
-
- /*
- * This structure describes the board.
- */
-
-struct tgafb_info {
- /* Use the generic framebuffer ops */
- struct fb_info_gen gen;
-
- /* Device dependent information */
- u8 tga_type; /* TGA_TYPE_XXX */
- u8 tga_chip_rev; /* dc21030 revision */
- u64 tga_mem_base;
- u64 tga_fb_base;
- u64 tga_regs_base;
- struct fb_var_screeninfo default_var; /* default video mode */
+struct tga_par {
+ /* PCI device. */
+ struct pci_dev *pdev;
+
+ /* Device dependent information. */
+ void *tga_mem_base;
+ void *tga_fb_base;
+ void *tga_regs_base;
+ u8 tga_type; /* TGA_TYPE_XXX */
+ u8 tga_chip_rev; /* dc21030 revision */
+
+ /* Remember blank mode. */
+ u8 vesa_blanked;
+
+ /* Define the video mode. */
+ u32 xres, yres; /* resolution in pixels */
+ u32 htimings; /* horizontal timing register */
+ u32 vtimings; /* vertical timing register */
+ u32 pll_freq; /* pixclock in mhz */
+ u32 bits_per_pixel; /* bits per pixel */
+ u32 sync_on_green; /* set if sync is on green */
};
- /*
- * This structure uniquely defines a video mode.
- */
+/*
+ * Macros for reading/writing TGA and RAMDAC registers
+ */
-struct tgafb_par {
- u32 xres, yres; /* resolution in pixels */
- u32 htimings; /* horizontal timing register */
- u32 vtimings; /* vertical timing register */
- u32 pll_freq; /* pixclock in mhz */
- u32 bits_per_pixel; /* bits per pixel */
- u32 sync_on_green; /* set if sync is on green */
-};
+static inline void
+TGA_WRITE_REG(struct tga_par *par, u32 v, u32 r)
+{
+ writel(v, par->tga_regs_base +r);
+}
+
+static inline u32
+TGA_READ_REG(struct tga_par *par, u32 r)
+{
+ return readl(par->tga_regs_base +r);
+}
+
+static inline void
+BT485_WRITE(struct tga_par *par, u8 v, u8 r)
+{
+ TGA_WRITE_REG(par, r, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, v | (r << 8), TGA_RAMDAC_REG);
+}
+
+static inline void
+BT463_LOAD_ADDR(struct tga_par *par, u16 a)
+{
+ TGA_WRITE_REG(par, BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, (BT463_ADDR_LO<<10) | (a & 0xff), TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, (BT463_ADDR_HI<<10) | (a >> 8), TGA_RAMDAC_REG);
+}
+
+static inline void
+BT463_WRITE(struct tga_par *par, u32 m, u16 a, u8 v)
+{
+ BT463_LOAD_ADDR(par, a);
+ TGA_WRITE_REG(par, m << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, m << 10 | v, TGA_RAMDAC_REG);
+}
#endif /* TGAFB_H */
diff --git a/kernel/printk.c b/kernel/printk.c
index cbe027aaf151..bb1bcb0d723f 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -638,7 +638,7 @@ void register_console(struct console * console)
}
if (console->flags & CON_PRINTBUFFER) {
/*
- * release_cosole_sem() will print out the buffered messages for us.
+ * release_console_sem() will print out the buffered messages for us.
*/
spin_lock_irqsave(&logbuf_lock, flags);
con_start = log_start;
diff --git a/scripts/ver_linux b/scripts/ver_linux
index edc3ec1f26a4..9fe09a9c7f94 100644
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -28,7 +28,7 @@ fdformat --version | awk -F\- '{print "util-linux ", $NF}'
mount --version | awk -F\- '{print "mount ", $NF}'
-insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}'
+rmmod -V 2>&1 | awk 'NR==1 {print "module-init-tools ",$NF}'
tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' | awk \
'NR==1 {print "e2fsprogs ", $2}'