From d6d05310c819d39ce14819a938a07109ad5c0c51 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 05:57:00 -0500 Subject: Updated to 2.5.48 --- include/asm-um/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index a8a7dfb7e4c8..0a24a9b5497f 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -164,7 +164,7 @@ static inline int clear_user(void *mem, int 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) +static inline int strnlen_user(const void *str, int len) { return(__do_strnlen_user(str, len, ¤t->thread.fault_addr, -- cgit v1.2.3 From 2f167bfa0c0317a0575dd7df2e651c61a1af1d63 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 18 Nov 2002 11:53:20 -0500 Subject: Merged a number of bug fixes from the 2.4 pool. --- arch/um/drivers/fd.c | 2 +- arch/um/drivers/mcast_kern.c | 4 ++-- arch/um/drivers/port_user.c | 2 +- arch/um/drivers/ubd_kern.c | 9 ++++++--- arch/um/drivers/xterm.c | 3 +++ arch/um/kernel/exitcode.c | 2 +- arch/um/kernel/helper.c | 5 ++++- arch/um/kernel/irq_user.c | 3 ++- arch/um/kernel/tty_log.c | 2 +- arch/um/os-Linux/file.c | 3 ++- include/asm-um/system-generic.h | 1 + 11 files changed, 24 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index e31620d15a77..efe5b6a0d476 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -30,7 +30,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); } 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/port_user.c b/arch/um/drivers/port_user.c index 35f163da9d32..23ee0a6d1398 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -40,7 +40,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); } diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 93228f048940..9198fcb1b2dd 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)) @@ -583,7 +586,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]; diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index e7b4ab83c8f7..f531010a128c 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -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); 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/helper.c b/arch/um/kernel/helper.c index 5d8fb7bba2b1..ede382d9b356 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -86,7 +86,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/irq_user.c b/arch/um/kernel/irq_user.c index a5abb61536cf..97575314113b 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, 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/os-Linux/file.c b/arch/um/os-Linux/file.c index 53e83d6607e1..ff024452f113 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); 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); -- cgit v1.2.3 From 46228a2bfeb95ec9635a41aff5e5f0e071c92d63 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Wed, 20 Nov 2002 13:04:22 -0500 Subject: Merged most of the rest of the skas changes. --- arch/um/Makefile | 56 ++-- arch/um/Makefile-i386 | 4 +- arch/um/drivers/chan_user.c | 35 +-- arch/um/drivers/pty.c | 2 +- arch/um/include/kern_util.h | 28 +- arch/um/include/mem_user.h | 12 +- arch/um/include/syscall_user.h | 13 +- arch/um/include/sysdep-i386/ptrace.h | 111 +++++-- arch/um/include/sysdep-i386/sigcontext.h | 33 +- arch/um/include/user_util.h | 23 +- arch/um/kernel/Makefile | 16 +- arch/um/kernel/exec_kern.c | 56 +--- arch/um/kernel/frame_kern.c | 5 +- arch/um/kernel/init_task.c | 2 +- arch/um/kernel/ksyms.c | 17 +- arch/um/kernel/mem.c | 47 +-- arch/um/kernel/mem_user.c | 44 +-- arch/um/kernel/process.c | 44 +-- arch/um/kernel/process_kern.c | 449 ++------------------------- arch/um/kernel/reboot.c | 25 +- arch/um/kernel/signal_kern.c | 6 +- arch/um/kernel/skas/Makefile | 27 ++ arch/um/kernel/skas/include/mode_kern.h | 52 ++++ arch/um/kernel/skas/mmu.c | 46 +++ arch/um/kernel/syscall_kern.c | 4 +- arch/um/kernel/syscall_user.c | 81 +---- arch/um/kernel/tlb.c | 34 +- arch/um/kernel/trap_kern.c | 248 +-------------- arch/um/kernel/trap_user.c | 453 ++------------------------- arch/um/kernel/tt/Makefile | 12 +- arch/um/kernel/tt/exec_kern.c | 6 +- arch/um/kernel/tt/gdb_kern.c | 40 +++ arch/um/kernel/tt/include/mode_kern.h | 53 ++++ arch/um/kernel/tt/mem.c | 77 +++++ arch/um/kernel/tt/process_kern.c | 512 +++++++++++++++++++++++++++++++ arch/um/kernel/um_arch.c | 60 ++-- arch/um/main.c | 64 +--- arch/um/os-Linux/process.c | 35 +++ arch/um/os-Linux/tty.c | 2 +- arch/um/sys-i386/ptrace_user.c | 2 +- arch/um/sys-i386/util/mk_thread_kern.c | 16 +- arch/um/sys-i386/util/mk_thread_user.c | 32 +- arch/um/util/Makefile | 11 +- include/asm-um/a.out.h | 8 +- include/asm-um/mmu.h | 18 +- include/asm-um/mmu_context.h | 51 ++- include/asm-um/processor-generic.h | 40 ++- 47 files changed, 1383 insertions(+), 1629 deletions(-) create mode 100644 arch/um/kernel/skas/Makefile create mode 100644 arch/um/kernel/skas/include/mode_kern.h create mode 100644 arch/um/kernel/skas/mmu.c create mode 100644 arch/um/kernel/tt/gdb_kern.c create mode 100644 arch/um/kernel/tt/include/mode_kern.h create mode 100644 arch/um/kernel/tt/mem.c create mode 100644 arch/um/kernel/tt/process_kern.c (limited to 'include') diff --git a/arch/um/Makefile b/arch/um/Makefile index bf9a4550947a..c202cad12325 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,27 +16,20 @@ 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)/ -ARCH_INCLUDE = $(ARCH_DIR)/include +ARCH_INCLUDE = -I$(ARCH_DIR)/include MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ -I$(ARCH_DIR)/kernel/skas/include @@ -40,8 +38,8 @@ MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ # 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 @@ -55,7 +53,13 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h -GEN_HEADERS = $(ARCH_DIR)/include/task.h +ifeq ($(CONFIG_MODE_SKAS), y) +GEN_HEADERS = $(ARCH_DIR)/kernel/skas/include/skas_ptregs.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) @@ -63,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 @@ -76,18 +80,20 @@ AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum linux: $(ARCH_DIR)/uml.lds.s vmlinux - $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -o $@ $(LINK_PROFILE) \ - $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil + $(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 $@ $< @@ -108,7 +114,6 @@ 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 @@ -133,9 +138,16 @@ $(ARCH_DIR)/include/uml-config.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/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 79879f30aef5..62d30a693f52 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; @@ -211,10 +187,9 @@ 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){ + pid = tcgetpgrp(fd); + 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/pty.c b/arch/um/drivers/pty.c index 6054dd6aa9ac..fc5f1d2f7d92 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -105,7 +105,7 @@ 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); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 076b94d75765..1567cb6a79dd 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -15,23 +15,27 @@ 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 unsigned long 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 +44,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 +60,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,9 +70,7 @@ 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); @@ -78,25 +78,19 @@ extern int init_ptrace_proxy(int idle_pid, int startup, int stop); extern int init_parent_proxy(int pid); 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/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/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 - -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/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/user_util.h b/arch/um/include/user_util.h index f4aea6b27411..f1d3bca2bd27 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -23,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; @@ -31,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; @@ -53,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); @@ -71,13 +71,13 @@ 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 init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); +extern void init_new_thread_signals(int altstack); extern void attach_process(int pid); -extern int fork_tramp(void *sig_stack); 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); @@ -91,7 +91,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 4fb60e8af16c..889fd82f1638 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o obj-$(CONFIG_MODE_TT) += tt/ -obj-$(CONFIG_MODE_SKAS) += tt/ +obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o @@ -28,7 +28,7 @@ user-objs-$(CONFIG_TTY_LOG) += tty_log.o 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),arch/um/kernel/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) @@ -51,24 +51,24 @@ include $(TOPDIR)/Rules.make $(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() { $$_ =~ 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 diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index cdbb95f6d0bd..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) diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index 574ddce69065..8726b2a1a439 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -43,7 +43,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if(restorer == NULL) panic("setup_signal_stack_si - no restorer"); - if(copy_sc_to_user((void *) sc, regs->regs.sc, + if(copy_sc_to_user((void *) sc, regs->regs.mode.tt, &signal_frame_sc.arch) || copy_to_user((void *) start, signal_frame_si.common.data, signal_frame_si.common.len) || @@ -86,7 +86,8 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, 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->regs.mode.tt, + &signal_frame_sc.arch) || 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, frame->sr_index, frame->sr_relative)) 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/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..3db5375ebe04 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; @@ -513,7 +516,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 +565,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 da86f77b0d96..1119d6b2b922 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -21,9 +21,6 @@ #include #include #include -#ifdef PROFILING -#include -#endif #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -33,13 +30,18 @@ #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" +#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 +49,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 +70,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 { @@ -128,26 +136,6 @@ void trace_myself(void) 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; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 8d9333e398d9..991b2097dc9d 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(task->thread.mode.tt.extern_pid); } 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,46 +101,6 @@ 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, ¤t->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; @@ -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(), 0); - - 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, 0); + 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()); -} - -void tracing_halt(void) -{ - current->thread.request.op = OP_HALT; - 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_cb(void (*proc)(void *), void *arg) +void initial_thread_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); + CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, + arg); } - + 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) @@ -602,22 +293,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"); @@ -644,16 +319,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 +329,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); @@ -762,7 +351,7 @@ int clear_user_proc(void *buf, int size) void set_thread_sc(void *sc) { - current->thread.regs.regs.sc = sc; + current->thread.regs.regs.mode.tt = sc; } int smp_sigio_handler(void) diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index a9b9a91b9afb..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, 0); + 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, 0); - } - if(init_task.thread.extern_pid != me) - os_kill_process(init_task.thread.extern_pid, 0); + 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(), 0); + CHOOSE_MODE(reboot_tt(), reboot_skas()); } void machine_power_off(void) { do_uml_exitcalls(); kill_off_processes(); - tracing_halt(); - os_kill_process(os_getpid(), 0); + CHOOSE_MODE(halt_tt(), halt_skas()); } void machine_halt(void) diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index be60440cf012..83db897787ee 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -171,7 +171,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(¤t->thread.regs))) - current->thread.singlestep_syscall = 1; + current->thread.mode.tt.singlestep_syscall = 1; return(0); } @@ -241,7 +241,7 @@ int sys_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, + copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, &signal_frame_sc.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } @@ -257,7 +257,7 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, + copy_sc_from_user(current->thread.regs.regs.mode.tt, sc, &signal_frame_sc.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile new file mode 100644 index 000000000000..cb83a2255fa9 --- /dev/null +++ b/arch/um/kernel/skas/Makefile @@ -0,0 +1,27 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ + syscall_user.o trap_user.o + +obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) + +USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +include $(TOPDIR)/Rules.make + +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/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h new file mode 100644 index 000000000000..dcbc70345a56 --- /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 mm_struct *mm, 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 thread_struct *thread); + +#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/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/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b15340a6b837..adc52d2dccf2 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -407,8 +407,8 @@ long execute_syscall(void *r) set_fs(USER_DS); - if(current->thread.singlestep_syscall){ - current->thread.singlestep_syscall = 0; + if(current->thread.mode.tt.singlestep_syscall){ + current->thread.mode.tt.singlestep_syscall = 0; current->ptrace &= ~PT_DTRACE; force_sig(SIGTRAP, current); } diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c index 5da5aefce6d8..00e8fcc10f27 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 +#include #include -#include -#include -#include -#include -#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/tlb.c b/arch/um/kernel/tlb.c index f5e8458ff866..000a26862ec5 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -30,8 +30,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long addr; int r, w, x, err; - if((current->thread.extern_pid != -1) && - (current->thread.extern_pid != os_getpid())) + 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; @@ -60,23 +60,25 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, w = 0; } if(force || pte_newpage(*npte)){ - err = unmap((void *) addr, PAGE_SIZE); + err = os_unmap_memory((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); + map_memory(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); } else if(pte_newprot(*npte)){ - protect(addr, PAGE_SIZE, r, w, x, 1); + protect_memory(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); + err = os_unmap_memory((void *) addr, PMD_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); @@ -106,24 +108,26 @@ void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) pte = pte_offset_kernel(pmd, addr); if(!pte_present(*pte) || pte_newpage(*pte)){ updated = 1; - err = unmap((void *) addr, PAGE_SIZE); + err = os_unmap_memory((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); + map_memory(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); + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); } addr += PAGE_SIZE; } else { if(pmd_newpage(*pmd)){ updated = 1; - err = unmap((void *) addr, PMD_SIZE); + err = os_unmap_memory((void *) addr, PMD_SIZE); if(err < 0) panic("munmap failed, errno = %d\n", -err); @@ -143,7 +147,7 @@ static void protect_vm_page(unsigned long addr, int w, int must_succeed) { int err; - err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed); + 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); @@ -207,8 +211,8 @@ void flush_tlb_mm(struct mm_struct *mm) fix_range(mm, 0, STACK_TOP, 0); seq = atomic_read(&vmchange_seq); - if(current->thread.vm_seq == seq) return; - current->thread.vm_seq = seq; + if(current->thread.mode.tt.vm_seq == seq) return; + current->thread.mode.tt.vm_seq = seq; flush_kernel_range(start_vm, end_vm, 0); } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 33bfc04fc5d0..5a9ed1c89478 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -117,7 +117,7 @@ out_of_memory: 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"); @@ -161,7 +161,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 +185,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=\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=\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..38872e7a288b 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -3,66 +3,33 @@ * Licensed under the GPL */ -#include #include -#include -#include #include -#include #include #include -#include -#include +#include #include -#include -#include #include +#include +#include #include #include #include -#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; -}; - -static struct signal_info sig_info[] = { +void usr2_handler(int sig, struct uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} + +struct signal_info sig_info[] = { [ SIGTRAP ] { handler : relay_signal, is_irq : 0 }, [ SIGFPE ] { handler : relay_signal, @@ -454,9 +90,9 @@ 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 }, }; @@ -472,7 +108,7 @@ void sig_handler_common(int sig, struct sigcontext *sc) save_regs = *r; is_user = user_context(SC_SP(sc)); r->is_user = is_user; - r->sc = sc; + r->mode.tt = sc; if(sig != SIGUSR2) r->syscall = -1; change_sig(SIGUSR1, 1); @@ -516,42 +152,13 @@ void alarm_handler(int sig, struct sigcontext sc) switch_timers(1); } -void do_longjmp(void *p) +void do_longjmp(void *p, int val) { jmp_buf *jbuf = (jmp_buf *) p; - longjmp(*jbuf, 1); -} - -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); + longjmp(*jbuf, val); } -__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 index 224f15c7ba54..8b0dd44a11c6 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,11 +3,17 @@ # Licensed under the GPL # -O_TARGET = tt.o - -obj-y = exec_kern.o exec_user.o +obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ + syscall_user.o tracer.o obj-$(CONFIG_PT_PROXY) += ptproxy/ +USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o tracer.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + include $(TOPDIR)/Rules.make +$(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 index b928324d7096..dd52d8751c5c 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -46,17 +46,17 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - if(current->processor == 0) + 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); + 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); + task_protections((unsigned long) current->thread_info); force_flush_all(); unblock_signals(); } 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/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h new file mode 100644 index 000000000000..7482e345f1c9 --- /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 mm_struct *mm, 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 thread_struct *thread); + +#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/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), + ¤t->thread.fault_addr, + ¤t->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..db9cfc294bb7 --- /dev/null +++ b/arch/um/kernel/tt/process_kern.c @@ -0,0 +1,512 @@ +/* + * 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 "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" + +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 *switch_to_tt(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.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]); +} + +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()); +} + +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, ¤t->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 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); +} + +/* 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 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 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); +} + +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.mode.tt.singlestep_syscall) + return(0); + return(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 thread_struct *thread) +{ + return(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/um_arch.c b/arch/um/kernel/um_arch.c index ba4410ad739b..eb5a5e6eef42 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -34,6 +34,9 @@ #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" @@ -44,7 +47,7 @@ struct cpuinfo_um boot_cpu_data = { unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(task->thread.extern_pid)); + return(os_process_pc(task->thread.mode.tt.extern_pid)); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -93,28 +96,6 @@ 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 @@ -128,12 +109,7 @@ static int start_kernel_proc(void *unused) 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 +132,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){ @@ -268,6 +245,7 @@ static void __init uml_postsetup(void) } extern int debug_trace; +int mode_tt = 1; /* Set during early boot */ unsigned long brk_start; @@ -280,7 +258,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,16 +267,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 = 1; + 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); @@ -334,8 +309,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(); @@ -343,9 +320,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/main.c b/arch/um/main.c index 204c7a189fdd..ffe6ed6f6289 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/process.c b/arch/um/os-Linux/process.c index 042df18a4eab..b7a565a2d721 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -95,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/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/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 -#include -#include -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/util/Makefile b/arch/um/util/Makefile index 96568b8ce61e..cde9e8ac75a5 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 include $(TOPDIR)/Rules.make @@ -8,6 +8,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/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/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/processor-generic.h b/include/asm-um/processor-generic.h index 7e771b8ca7db..596257f5bd15 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,8 +22,24 @@ struct mm_struct; #define cpu_relax() do ; while (0) +#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 extern_pid; int tracing; int forking; unsigned long kernel_stack; @@ -33,13 +49,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 +81,6 @@ struct thread_struct { #define INIT_THREAD \ { \ - extern_pid: -1, \ - tracing: 0, \ forking: 0, \ kernel_stack: 0, \ nsyscalls: 0, \ @@ -69,13 +88,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 } \ } -- cgit v1.2.3 From 3817da1371de54bca1b8a3980647f3bfc6f4858b Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 08:54:16 -0500 Subject: Added the uaccess changes from the skas merge. --- arch/um/include/um_uaccess.h | 73 +++++++++++ arch/um/kernel/skas/include/uaccess.h | 239 ++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/Makefile | 2 +- arch/um/kernel/tt/include/uaccess.h | 119 +++++++++++++++++ arch/um/kernel/tt/uaccess_user.c | 126 ++++++++++++++++++ arch/um/kernel/uaccess_user.c | 126 ------------------ include/asm-um/uaccess.h | 100 +------------- 7 files changed, 560 insertions(+), 225 deletions(-) create mode 100644 arch/um/include/um_uaccess.h create mode 100644 arch/um/kernel/skas/include/uaccess.h create mode 100644 arch/um/kernel/tt/include/uaccess.h create mode 100644 arch/um/kernel/tt/uaccess_user.c delete mode 100644 arch/um/kernel/uaccess_user.c (limited to 'include') diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h new file mode 100644 index 000000000000..b12802b8cde7 --- /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(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/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h new file mode 100644 index 000000000000..7657c828f3c4 --- /dev/null +++ b/arch/um/kernel/skas/include/uaccess.h @@ -0,0 +1,239 @@ +/* + * 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 "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 unsigned long handle_page_fault(unsigned long address, + unsigned long ip, int is_write, + int is_user, int *code_out); + +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(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/tt/Makefile b/arch/um/kernel/tt/Makefile index 8b0dd44a11c6..401ae1f4f59d 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -4,7 +4,7 @@ # obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o mem.o process_kern.o \ - syscall_user.o tracer.o + syscall_user.o tracer.o uaccess_user.o obj-$(CONFIG_PT_PROXY) += ptproxy/ diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h new file mode 100644 index 000000000000..7eae8c819d01 --- /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, + ¤t->thread.fault_addr, + ¤t->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, + ¤t->thread.fault_addr, + ¤t->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, + ¤t->thread.fault_addr, + ¤t->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, + ¤t->thread.fault_addr, + ¤t->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, + ¤t->thread.fault_addr, + ¤t->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(void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t->thread.fault_addr, + ¤t->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/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c new file mode 100644 index 000000000000..639ea1c4be37 --- /dev/null +++ b/arch/um/kernel/tt/uaccess_user.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) + * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "user_util.h" + +static unsigned long __do_user_copy(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher, + void (*op)(void *to, const void *from, + int n), int *faulted_out) +{ + unsigned long *faddrp = (unsigned long *) fault_addr, ret; + + jmp_buf jbuf; + *fault_catcher = &jbuf; + if(setjmp(jbuf) == 0){ + (*op)(to, from, n); + ret = 0; + *faulted_out = 0; + } + else { + ret = *faddrp; + *faulted_out = 1; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +static void __do_copy(void *to, const void *from, int n) +{ + memcpy(to, from, n); +} + +int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy, &faulted); + if(!faulted) return(0); + else return(n - (fault - (unsigned long) from)); +} + + +int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy, &faulted); + if(!faulted) return(0); + else return(n - (fault - (unsigned long) to)); +} + +static void __do_strncpy(void *dst, const void *src, int count) +{ + strncpy(dst, src, count); +} + +int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, + __do_strncpy, &faulted); + if(!faulted) return(strlen(dst)); + else return(-1); +} + +static void __do_clear(void *to, const void *from, int n) +{ + memset(to, 0, n); +} + +int __do_clear_user(void *mem, unsigned long len, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, + __do_clear, &faulted); + if(!faulted) return(0); + else return(len - (fault - (unsigned long) mem)); +} + +int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher) +{ + int ret; + unsigned long *faddrp = (unsigned long *)fault_addr; + jmp_buf jbuf; + + *fault_catcher = &jbuf; + if(setjmp(jbuf) == 0){ + ret = strlen(str) + 1; + } + else { + ret = *faddrp - (unsigned long) str; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + +/* + * 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/uaccess_user.c deleted file mode 100644 index 639ea1c4be37..000000000000 --- a/arch/um/kernel/uaccess_user.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include "user_util.h" - -static unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - jmp_buf jbuf; - *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - -static void __do_copy(void *to, const void *from, int n) -{ - memcpy(to, from, n); -} - -int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) from)); -} - - -int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) to)); -} - -static void __do_strncpy(void *dst, const void *src, int count) -{ - strncpy(dst, src, count); -} - -int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, - __do_strncpy, &faulted); - if(!faulted) return(strlen(dst)); - else return(-1); -} - -static void __do_clear(void *to, const void *from, int n) -{ - memset(to, 0, n); -} - -int __do_clear_user(void *mem, unsigned long len, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, - __do_clear, &faulted); - if(!faulted) return(0); - else return(len - (fault - (unsigned long) mem)); -} - -int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher) -{ - int ret; - unsigned long *faddrp = (unsigned long *)fault_addr; - jmp_buf jbuf; - - *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ - ret = strlen(str) + 1; - } - else { - ret = *faddrp - (unsigned long) str; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - -/* - * 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/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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user(void *mem, int len) -{ - return(access_ok(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->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, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - #define strlen_user(str) strnlen_user(str, ~0UL >> 1) struct exception_table_entry -- cgit v1.2.3 From 7ee0eebf1138a64d9aac60ab93f9ec1e3494a247 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 21 Nov 2002 12:30:24 -0500 Subject: Merged the IP checksum changes from the skas code. --- arch/um/include/sysdep-i386/checksum.h | 217 +++++++++++++++++++++++++++++++++ arch/um/kernel/checksum.c | 42 +++++++ arch/um/sys-i386/ksyms.c | 3 +- include/asm-um/checksum.h | 2 +- 4 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 arch/um/include/sysdep-i386/checksum.h create mode 100644 arch/um/kernel/checksum.c (limited to 'include') 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 , 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/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/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/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 -- cgit v1.2.3 From 30768623c1f7594feb5a4883ac8de792ce95a571 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 04:27:24 -0500 Subject: Minor build fixes to the last batch of skas merges. --- arch/um/kernel/skas/Makefile | 5 +++-- arch/um/kernel/skas/mem.c | 35 +++++++++++++++++++++++++++++++++++ arch/um/kernel/tt/syscall_kern.c | 3 --- include/asm-um/ptrace-generic.h | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 arch/um/kernel/skas/mem.c (limited to 'include') diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index a58e13b91b6f..97544aa29d1e 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,8 +3,9 @@ # Licensed under the GPL # -obj-y = exec_kern.o exec_user.o mem_user.o mmu.o process.o process_kern.o \ - syscall_kern.o syscall_user.o time.o trap_user.o sys-$(SUBARCH)/ +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 trap_user.o \ + sys-$(SUBARCH)/ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) 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/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 463955bde899..dd087fb96ff6 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -98,9 +98,6 @@ static int check_bogosity(struct pt_regs *regs) 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_tt(void *r) 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 -- cgit v1.2.3 From 41fb3bb0728d67c7646bc45296d3454e9af4aad2 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 22 Nov 2002 11:47:15 -0500 Subject: Merged the rest of the skas changes. --- arch/um/kernel/um_arch.c | 64 ++++++++++++++++++++++++++++++++++-------------- include/asm-um/page.h | 2 ++ 2 files changed, 47 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index eb5a5e6eef42..50c3f6313e16 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -41,13 +41,14 @@ #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.mode.tt.extern_pid)); + return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, + thread))); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -96,16 +97,7 @@ pte_t * __bad_pagetable(void) return(NULL); } -#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; @@ -192,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; @@ -244,9 +273,6 @@ static void __init uml_postsetup(void) return; } -extern int debug_trace; -int mode_tt = 1; - /* Set during early boot */ unsigned long brk_start; static struct vm_reserved kernel_vm_reserved; @@ -267,7 +293,7 @@ int linux_main(int argc, char **argv) } if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); - mode_tt = 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); 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 -- cgit v1.2.3 From 0fc3a8cde0a53af12f9f9566b0304439b83e4d97 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Nov 2002 11:03:24 -0500 Subject: Small fixes to sync up the 2.4 and 2.5 pools. Also fixed a stupid signal handling bug. --- arch/um/drivers/chan_user.c | 2 +- arch/um/include/user_util.h | 1 - arch/um/kernel/frame_kern.c | 10 ++-- arch/um/kernel/process.c | 44 +++------------ arch/um/kernel/skas/include/skas.h | 1 + arch/um/kernel/skas/process.c | 23 ++++++++ arch/um/kernel/skas/trap_user.c | 2 + arch/um/kernel/syscall_user.c | 8 +-- arch/um/kernel/trap_user.c | 8 +-- arch/um/kernel/tt/gdb.c | 19 +++++-- arch/um/kernel/tt/include/debug.h | 3 ++ arch/um/kernel/tt/process_kern.c | 106 ++++++++++++++++++------------------- arch/um/kernel/tt/ptproxy/Makefile | 1 - arch/um/kernel/tt/tlb.c | 11 ++-- arch/um/kernel/tt/tracer.c | 5 +- arch/um/main.c | 6 +-- include/asm-um/processor-generic.h | 5 +- 17 files changed, 132 insertions(+), 123 deletions(-) (limited to 'include') diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 62d30a693f52..e06f20a14877 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -187,7 +187,7 @@ void register_winch(int fd, void *device_data) if(!isatty(fd)) return; - pid = tcgetpgrp(fd); + pid = tcgetpgrp(fd); if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index f1d3bca2bd27..a419cc9ccfff 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -73,7 +73,6 @@ extern void setup_hostinfo(void); extern void add_arg(char *cmd_line, char *arg); extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); extern void init_new_thread_signals(int altstack); -extern void attach_process(int pid); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index b7abbf55498c..cd2177629bec 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -29,11 +29,11 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, 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))); + 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, diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 1119d6b2b922..44e9a980949f 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -39,6 +39,7 @@ #include "mode.h" #ifdef CONFIG_MODE_SKAS #include "skas_ptrace.h" +#include "skas.h" #endif void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) @@ -130,12 +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 suspend_new_thread(int fd) { char c; @@ -227,19 +222,19 @@ void __init check_ptrace(void) break; } } - stop_ptraced_child(pid, stack, 0); + 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; + int n; *jmp_ptr = &buf; - n = setjmp(buf); - if(n != 0) - return(n); + n = setjmp(buf); + if(n != 0) + return(n); (*fn)(arg); return(0); } @@ -254,31 +249,6 @@ void forward_pending_sigio(int target) kill(target, SIGIO); } -#ifdef CONFIG_MODE_SKAS -static 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); -} -#endif - int can_do_skas(void) { #ifdef CONFIG_MODE_SKAS @@ -311,7 +281,7 @@ int can_do_skas(void) return(ret); #else return(0); -#endif +#endif } /* diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index 6732307894d5..e733b0c87448 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -33,6 +33,7 @@ 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 diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 5c72105d84dd..15a1fd345178 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -351,6 +351,29 @@ 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 diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index b93e93a71e8e..e906e5a630cb 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -50,6 +50,8 @@ void user_signal(int sig, struct uml_pt_regs *regs) regs->mode.skas.trap_type = 0; info = &sig_info[sig]; (*info->handler)(sig, regs); + + unblock_signals(); } /* diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c index 00e8fcc10f27..3712286fe5cb 100644 --- a/arch/um/kernel/syscall_user.c +++ b/arch/um/kernel/syscall_user.c @@ -18,8 +18,8 @@ struct { int record_syscall_start(int syscall) { - int max, index; - + int max, index; + max = sizeof(syscall_record)/sizeof(syscall_record[0]); index = next_syscall_index(max); @@ -32,8 +32,8 @@ int record_syscall_start(int syscall) void record_syscall_end(int index, int result) { - syscall_record[index].result = result; - gettimeofday(&syscall_record[index].end, NULL); + syscall_record[index].result = result; + gettimeofday(&syscall_record[index].end, NULL); } /* diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 925aacf560f3..02e7b0eede15 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -74,7 +74,7 @@ void usr2_handler(int sig, struct uml_pt_regs *regs) { CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); } - + struct signal_info sig_info[] = { [ SIGTRAP ] { handler : relay_signal, is_irq : 0 }, @@ -119,11 +119,11 @@ void alarm_handler(int sig, struct sigcontext sc) switch_timers(1); } -void do_longjmp(void *p, int val) +void do_longjmp(void *b, int val) { - jmp_buf *jbuf = (jmp_buf *) p; + jmp_buf *buf = b; - longjmp(*jbuf, val); + longjmp(*buf, val); } /* diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 1e819be2539b..22753784178a 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c @@ -117,7 +117,7 @@ struct gdb_data { static void config_gdb_cb(void *arg) { struct gdb_data *data = arg; - struct task_struct *task; + void *task; int pid; data->err = -1; @@ -228,19 +228,19 @@ 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"); + 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(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); + printk(UM_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 " + printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " "is off\n"); return(-1); } @@ -265,3 +265,14 @@ 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/include/debug.h b/arch/um/kernel/tt/include/debug.h index 1d8b0a2638a8..8eff674107ca 100644 --- a/arch/um/kernel/tt/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/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 5b4b285f8cd4..683e2d35cac5 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -24,30 +24,11 @@ #include "init.h" #include "tt.h" -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 *switch_to_tt(void *prev, void *next, void *last) { struct task_struct *from, *to; unsigned long flags; - int vtalrm, alrm, prof, err, cpu; + int err, vtalrm, alrm, prof, cpu; char c; /* jailing and SMP are incompatible, so this doesn't need to be * made per-cpu @@ -60,7 +41,7 @@ void *switch_to_tt(void *prev, void *next, void *last) to->thread.prev_sched = from; cpu = from->thread_info->cpu; - if(cpu == 0) + 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); @@ -130,18 +111,6 @@ void exit_thread_tt(void) close(current->thread.mode.tt.switch_pipe[1]); } -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()); -} - extern void schedule_tail(struct task_struct *prev); static void new_thread_handler(int sig) @@ -276,6 +245,32 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, 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){ @@ -395,7 +390,6 @@ static void mprotect_kernel_mem(int w) mprotect_kernel_vm(w); } -/* No SMP problems since jailing and SMP are incompatible */ void unprotect_kernel_mem(void) { mprotect_kernel_mem(1); @@ -406,18 +400,23 @@ void protect_kernel_mem(void) mprotect_kernel_mem(0); } -void kill_off_processes_tt(void) +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) { - struct task_struct *p; - int me; + int pid; - 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); + 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) @@ -435,7 +434,8 @@ int set_user_mode(void *t) struct task_struct *task; task = t ? t : current; - if(task->thread.mode.tt.tracing) return(1); + if(task->thread.mode.tt.tracing) + return(1); task->thread.request.op = OP_TRACE_ON; os_usr1_process(os_getpid()); return(0); @@ -451,22 +451,22 @@ void set_init_pid(int pid) err); } -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; + 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; diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile index cf94d8b61c88..10eb5b00f39a 100644 --- a/arch/um/kernel/tt/ptproxy/Makefile +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -13,4 +13,3 @@ $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean: - rm -f *.o core child ptproxy diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index fbe0a4fd3915..e7e95a5c6ad2 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -84,7 +84,8 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, atomic_t vmchange_seq = ATOMIC_INIT(1); -void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) +static void flush_kernel_vm_range(unsigned long start, unsigned long end, + int update_seq) { struct mm_struct *mm; pgd_t *pgd; @@ -133,7 +134,7 @@ void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - flush_kernel_range(start, end, 1); + flush_kernel_vm_range(start, end, 1); } static void protect_vm_page(unsigned long addr, int w, int must_succeed) @@ -189,7 +190,7 @@ void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, * either process memory or kernel vm */ if((start >= start_vm) && (start < end_vm)) - flush_kernel_range(start, end, 1); + flush_kernel_vm_range(start, end, 1); else fix_range(vma->vm_mm, start, end, 0); } @@ -204,13 +205,13 @@ void flush_tlb_mm_tt(struct mm_struct *mm) seq = atomic_read(&vmchange_seq); if(current->thread.mode.tt.vm_seq == seq) return; current->thread.mode.tt.vm_seq = seq; - flush_kernel_range(start_vm, end_vm, 0); + 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_range(start_vm, end_vm, 0); + flush_kernel_vm_range(start_vm, end_vm, 0); } /* diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 5b06c48e45b7..90e948c836bb 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -372,13 +372,14 @@ int tracer(int (*init_proc)(void *), void *sp) if(!tracing && (debugger_pid != -1) && (sig != 0) && (sig != SIGALRM) && (sig != SIGVTALRM) && (sig != SIGSEGV) && (sig != SIGTRAP) && - (sig != SIGUSR2) && (sig != SIGIO)){ + (sig != SIGUSR2) && (sig != SIGIO) && + (sig != SIGFPE)){ child_signal(pid, status); continue; } if(tracing){ - if(singlestepping(task)) + if(singlestepping_tt(task)) cont_type = PTRACE_SINGLESTEP; else cont_type = PTRACE_SYSCALL; } diff --git a/arch/um/main.c b/arch/um/main.c index ffe6ed6f6289..3addff95120c 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -135,13 +135,13 @@ int main(int argc, char **argv, char **envp) } #define CAN_KMALLOC() \ - (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) + (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) extern void *__real_malloc(int); void *__wrap_malloc(int size) { - if(CAN_KMALLOC()) return(um_kmalloc(size)); + if(CAN_KMALLOC()) return(um_kmalloc(size)); else return(__real_malloc(size)); } @@ -158,7 +158,7 @@ extern void __real_free(void *); void __wrap_free(void *ptr) { - if(CAN_KMALLOC()) kfree(ptr); + if(CAN_KMALLOC()) kfree(ptr); else __real_free(ptr); } diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 596257f5bd15..435380cc08d7 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -24,8 +24,8 @@ struct mm_struct; #ifdef CONFIG_MODE_TT struct proc_tt_mode { - int extern_pid; - int tracing; + int extern_pid; + int tracing; int switch_pipe[2]; int singlestep_syscall; int vm_seq; @@ -40,7 +40,6 @@ struct proc_skas_mode { #endif struct thread_struct { - int tracing; int forking; unsigned long kernel_stack; int nsyscalls; -- cgit v1.2.3 From d3f34f89e958a8ca6cce54d5ba76a7c6b40b6d39 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 6 Dec 2002 11:23:55 -0500 Subject: Updated to 2.5.50. --- arch/um/kernel/ptrace.c | 3 +-- arch/um/kernel/sys_call_table.c | 1 + include/asm-um/pgtable.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index d6dacf475c33..8b5739a84ed3 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -33,8 +33,7 @@ int sys_ptrace(long request, long pid, long addr, long data) if (current->ptrace & PT_PTRACED) goto out; - ret = security_ptrace(current->parent, current); - if (ret) + if((ret = security_ptrace(current->parent, current))) goto out; /* set the ptrace bit in the process flags. */ diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 9418e8e329f6..14b4e4c066b6 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -8,6 +8,7 @@ #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" 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; -- cgit v1.2.3 From 2e7fa3fb6089f4c7f847d919cb9806f86836bc7f Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 16 Dec 2002 14:44:15 -0500 Subject: Applied updates from 2.5.51 and 2.5.52. --- arch/um/kernel/ptrace.c | 3 ++- arch/um/kernel/signal_kern.c | 7 +++++++ arch/um/kernel/sys_call_table.c | 2 +- arch/um/kernel/syscall_kern.c | 6 +++++- arch/um/uml.lds.S | 11 ++++++++++- include/asm-um/thread_info.h | 10 ++++------ 6 files changed, 29 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 8b5739a84ed3..d6dacf475c33 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -33,7 +33,8 @@ int sys_ptrace(long request, long pid, long addr, long data) if (current->ptrace & PT_PTRACED) goto out; - if((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index be60440cf012..87768b9661aa 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -69,6 +69,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 +163,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 diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 7b5a703a24c7..9a329a4938ab 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -254,7 +254,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, diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index ab42524562b1..1cf0ed074e2a 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -182,7 +182,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: { diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S index cd4b487e0fa5..736df4695129 100644 --- a/arch/um/uml.lds.S +++ b/arch/um/uml.lds.S @@ -59,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/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) -- cgit v1.2.3 From 6898c902b76b3d55022a44da95fbe38569458dd9 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Wed, 25 Dec 2002 21:55:05 -0800 Subject: [PATCH] amd756 and amd8111 sensors support Add support for amd756 and amd8111 sensors --- MAINTAINERS | 9 + drivers/Makefile | 2 + drivers/char/mem.c | 13 + drivers/i2c/Kconfig | 3 + drivers/i2c/busses/Kconfig | 56 +++ drivers/i2c/busses/Makefile | 7 + drivers/i2c/busses/i2c-amd756.c | 526 ++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-amd8111.c | 425 +++++++++++++++++++++++ drivers/i2c/busses/i2c-mainboard.c | 34 ++ drivers/i2c/chips/Kconfig | 54 +++ drivers/i2c/chips/Makefile | 7 + drivers/i2c/chips/adm1021.c | 633 ++++++++++++++++++++++++++++++++++ drivers/i2c/chips/lm75.c | 403 ++++++++++++++++++++++ drivers/i2c/chips/sensors.c | 37 ++ drivers/i2c/i2c-core.c | 15 +- drivers/i2c/i2c-dev.c | 15 +- drivers/i2c/i2c-proc.c | 60 +++- include/linux/i2c-id.h | 1 + include/linux/i2c-proc.h | 25 ++ include/linux/sensors.h | 690 +++++++++++++++++++++++++++++++++++++ 20 files changed, 3003 insertions(+), 12 deletions(-) create mode 100644 drivers/i2c/busses/Kconfig create mode 100644 drivers/i2c/busses/Makefile create mode 100644 drivers/i2c/busses/i2c-amd756.c create mode 100644 drivers/i2c/busses/i2c-amd8111.c create mode 100644 drivers/i2c/busses/i2c-mainboard.c create mode 100644 drivers/i2c/chips/Kconfig create mode 100644 drivers/i2c/chips/Makefile create mode 100644 drivers/i2c/chips/adm1021.c create mode 100644 drivers/i2c/chips/lm75.c create mode 100644 drivers/i2c/chips/sensors.c create mode 100644 include/linux/sensors.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 8e382197d494..e8b5a59b5353 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -762,6 +762,15 @@ L: linux-i2c@pelican.tk.uni-linz.ac.at W: http://www.tk.uni-linz.ac.at/~simon/private/i2c S: Maintained +SENSORS DRIVERS +P: Frodo Looijaard +M: frodol@dds.nl +P: Philip Edelbrock +M: phil@netroedge.com +L: sensors@stimpy.netroedge.com +W: http://www.lm-sensors.nu/ +S: Maintained + i386 BOOT CODE P: Riley H. Williams M: Riley@Williams.Name diff --git a/drivers/Makefile b/drivers/Makefile index a6ce89683e2c..07c756c046b8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ +obj-$(CONFIG_I2C_MAINBOARD) += i2c/busses/ +obj-$(CONFIG_SENSORS) += i2c/chips/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3df145966b6d..0e97b489d17b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -27,6 +27,12 @@ #include #include +#ifdef CONFIG_I2C_MAINBOARD +extern void i2c_mainboard_init_all(void); +#endif +#ifdef CONFIG_SENSORS +extern void sensors_init_all(void); +#endif #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif @@ -705,6 +711,9 @@ int __init chr_dev_init(void) #ifdef CONFIG_I2C i2c_init_all(); #endif +#ifdef CONFIG_I2C_MAINBOARD + i2c_mainboard_init_all(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -719,6 +728,10 @@ int __init chr_dev_init(void) #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) tapechar_init(); #endif +#ifdef CONFIG_SENSORS + sensors_init_all(); +#endif + return 0; } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 131f4c901af5..206f7c5f2ed4 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -193,5 +193,8 @@ config I2C_PROC it as a module, say M here and read . The module will be called i2c-proc.o. + source drivers/i2c/busses/Kconfig + source drivers/i2c/chips/Kconfig + endmenu diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig new file mode 100644 index 000000000000..b6bf9ee09ff2 --- /dev/null +++ b/drivers/i2c/busses/Kconfig @@ -0,0 +1,56 @@ +# +# Sensor device configuration +# All depend on EXPERIMENTAL, I2C and I2C_PROC. +# + +menu "I2C Hardware Sensors Mainboard support" + +config I2C_MAINBOARD + bool "Hardware sensors mainboard support" + depends on EXPERIMENTAL && I2C && I2C_PROC + help + Many modern mainboards have some kind of I2C interface integrated. This + is often in the form of a SMBus, or System Management Bus, which is + basically the same as I2C but which uses only a subset of the I2C + protocol. + + You will also want the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config I2C_AMD756 + tristate " AMD 756/766" + depends on I2C_MAINBOARD + help + If you say yes to this option, support will be included for the AMD + 756/766/768 mainboard I2C interfaces. + + This can also be built as a module which can be inserted and removed + while the kernel is running. If you want to compile it as a module, + say M here and read . + + The module will be called i2c-amd756.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config I2C_AMD8111 + tristate " AMD 8111" + depends on I2C_MAINBOARD + help + If you say yes to this option, support will be included for the AMD + 8111 mainboard I2C interfaces. + + This can also be built as a module which can be inserted and removed + while the kernel is running. If you want to compile it as a module, + say M here and read . + + The module will be called i2c-amd8111.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +endmenu + diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile new file mode 100644 index 000000000000..75d4babc375c --- /dev/null +++ b/drivers/i2c/busses/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the kernel hardware sensors bus drivers. +# + +obj-$(CONFIG_I2C_MAINBOARD) += i2c-mainboard.o +obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o +obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c new file mode 100644 index 000000000000..db08bdc56430 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd756.c @@ -0,0 +1,526 @@ +/* + amd756.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 1999-2002 Merlin Hughes + + Shamelessly ripped from i2c-piix4.c: + + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + 2002-04-08: Added nForce support. (Csaba Halasz) + 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil) +*/ + +/* + Supports AMD756, AMD766, AMD768 and nVidia nForce + Note: we assume there can only be one device, with one SMBus interface. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sd { + const unsigned short vendor; + const unsigned short device; + const unsigned short function; + const char* name; + int amdsetup:1; +}; + +static struct sd supported[] = { + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B, 3, "AMD756", 1}, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 3, "AMD766", 1}, + {PCI_VENDOR_ID_AMD, 0x7443, 3, "AMD768", 1}, + {PCI_VENDOR_ID_NVIDIA, 0x01B4, 1, "nVidia nForce", 0}, + {0, 0, 0} +}; + +/* AMD756 SMBus address offsets */ +#define SMB_ADDR_OFFSET 0xE0 +#define SMB_IOSIZE 16 +#define SMB_GLOBAL_STATUS (0x0 + amd756_smba) +#define SMB_GLOBAL_ENABLE (0x2 + amd756_smba) +#define SMB_HOST_ADDRESS (0x4 + amd756_smba) +#define SMB_HOST_DATA (0x6 + amd756_smba) +#define SMB_HOST_COMMAND (0x8 + amd756_smba) +#define SMB_HOST_BLOCK_DATA (0x9 + amd756_smba) +#define SMB_HAS_DATA (0xA + amd756_smba) +#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_smba) +#define SMB_HAS_HOST_ADDRESS (0xE + amd756_smba) +#define SMB_SNOOP_ADDRESS (0xF + amd756_smba) + +/* PCI Address Constants */ + +/* address of I/O space */ +#define SMBBA 0x058 /* mh */ +#define SMBBANFORCE 0x014 + +/* general configuration */ +#define SMBGCFG 0x041 /* mh */ + +/* silicon revision code */ +#define SMBREV 0x008 + +/* Other settings */ +#define MAX_TIMEOUT 500 + +/* AMD756 constants */ +#define AMD756_QUICK 0x00 +#define AMD756_BYTE 0x01 +#define AMD756_BYTE_DATA 0x02 +#define AMD756_WORD_DATA 0x03 +#define AMD756_PROCESS_CALL 0x04 +#define AMD756_BLOCK_DATA 0x05 + +/* insmod parameters */ + +int __init i2c_amd756_init(void); +void __exit i2c_amd756_exit(void); +static int amd756_cleanup(void); + +static int amd756_setup(void); +static s32 amd756_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); +static void amd756_do_pause(unsigned int amount); +static void amd756_abort(void); +static int amd756_transaction(void); +static void amd756_inc(struct i2c_adapter *adapter); +static void amd756_dec(struct i2c_adapter *adapter); +static u32 amd756_func(struct i2c_adapter *adapter); + +static struct i2c_algorithm smbus_algorithm = { + /* name */ "Non-I2C SMBus adapter", + /* id */ I2C_ALGO_SMBUS, + /* master_xfer */ NULL, + /* smbus_access */ amd756_access, + /* slave;_send */ NULL, + /* slave_rcv */ NULL, + /* algo_control */ NULL, + /* functionality */ amd756_func, +}; + +static struct i2c_adapter amd756_adapter = { + "unset", + I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, + &smbus_algorithm, + NULL, + amd756_inc, + amd756_dec, + NULL, + NULL, +}; + +static int __initdata amd756_initialized; +static struct sd *amd756_sd = NULL; +static unsigned short amd756_smba = 0; + +int amd756_setup(void) +{ + unsigned char temp; + struct sd *currdev; + struct pci_dev *AMD756_dev = NULL; + + if (pci_present() == 0) { + return -ENODEV; + } + + /* Look for a supported chip */ + for(currdev = supported; currdev->vendor; ) { + AMD756_dev = pci_find_device(currdev->vendor, + currdev->device, AMD756_dev); + if (AMD756_dev != NULL) { + if (PCI_FUNC(AMD756_dev->devfn) == currdev->function) + break; + } else { + currdev++; + } + } + + if (AMD756_dev == NULL) { + printk + ("i2c-amd756.o: Error: No AMD756 or compatible device detected!\n"); + return -ENODEV; + } + printk(KERN_INFO "i2c-amd756.o: Found %s SMBus controller.\n", currdev->name); + + if (currdev->amdsetup) + { + pci_read_config_byte(AMD756_dev, SMBGCFG, &temp); + if ((temp & 128) == 0) { + printk("i2c-amd756.o: Error: SMBus controller I/O not enabled!\n"); + return -ENODEV; + } + + /* Determine the address of the SMBus areas */ + /* Technically it is a dword but... */ + pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba); + amd756_smba &= 0xff00; + amd756_smba += SMB_ADDR_OFFSET; + } else { + pci_read_config_word(AMD756_dev, SMBBANFORCE, &amd756_smba); + amd756_smba &= 0xfffc; + } + if(amd756_smba == 0) { + printk(KERN_ERR "i2c-amd756.o: Error: SMB base address uninitialized\n"); + return -ENODEV; + } + if (check_region(amd756_smba, SMB_IOSIZE)) { + printk + ("i2c-amd756.o: SMB region 0x%x already in use!\n", + amd756_smba); + return -ENODEV; + } + + /* Everything is happy, let's grab the memory and set things up. */ + request_region(amd756_smba, SMB_IOSIZE, "amd756-smbus"); + +#ifdef DEBUG + pci_read_config_byte(AMD756_dev, SMBREV, &temp); + printk("i2c-amd756.o: SMBREV = 0x%X\n", temp); + printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba); +#endif /* DEBUG */ + + /* store struct sd * for future reference */ + amd756_sd = currdev; + + return 0; +} + +/* + SMBUS event = I/O 28-29 bit 11 + see E0 for the status bits and enabled in E2 + +*/ + +/* Internally used pause function */ +void amd756_do_pause(unsigned int amount) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(amount); +} + +#define GS_ABRT_STS (1 << 0) +#define GS_COL_STS (1 << 1) +#define GS_PRERR_STS (1 << 2) +#define GS_HST_STS (1 << 3) +#define GS_HCYC_STS (1 << 4) +#define GS_TO_STS (1 << 5) +#define GS_SMB_STS (1 << 11) + +#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ + GS_HCYC_STS | GS_TO_STS ) + +#define GE_CYC_TYPE_MASK (7) +#define GE_HOST_STC (1 << 3) +#define GE_ABORT (1 << 5) + +void amd756_abort(void) +{ + printk("i2c-amd756.o: Sending abort.\n"); + outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); + amd756_do_pause(100); + outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); +} + +int amd756_transaction(void) +{ + int temp; + int result = 0; + int timeout = 0; + +#ifdef DEBUG + printk + ("i2c-amd756.o: Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); +#endif + + /* Make sure the SMBus host is ready to start transmitting */ + if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { +#ifdef DEBUG + printk + ("i2c-amd756.o: SMBus busy (%04x). Waiting... \n", temp); +#endif + do { + amd756_do_pause(1); + temp = inw_p(SMB_GLOBAL_STATUS); + } while ((temp & (GS_HST_STS | GS_SMB_STS)) && + (timeout++ < MAX_TIMEOUT)); + /* If the SMBus is still busy, we give up */ + if (timeout >= MAX_TIMEOUT) { + printk("i2c-amd756.o: Busy wait timeout! (%04x)\n", temp); + amd756_abort(); + return -1; + } + timeout = 0; + } + + /* start the transaction by setting the start bit */ + outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE); + + /* We will always wait for a fraction of a second! */ + do { + amd756_do_pause(1); + temp = inw_p(SMB_GLOBAL_STATUS); + } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT)); + + /* If the SMBus is still busy, we give up */ + if (timeout >= MAX_TIMEOUT) { + printk("i2c-amd756.o: Completion timeout!\n"); + amd756_abort (); + return -1; + } + + if (temp & GS_PRERR_STS) { + result = -1; +#ifdef DEBUG + printk("i2c-amd756.o: SMBus Protocol error (no response)!\n"); +#endif + } + + if (temp & GS_COL_STS) { + result = -1; + printk("i2c-amd756.o: SMBus collision!\n"); + } + + if (temp & GS_TO_STS) { + result = -1; +#ifdef DEBUG + printk("i2c-amd756.o: SMBus protocol timeout!\n"); +#endif + } +#ifdef DEBUG + if (temp & GS_HCYC_STS) { + printk("i2c-amd756.o: SMBus protocol success!\n"); + } +#endif + + outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); + +#ifdef DEBUG + if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { + printk + ("i2c-amd756.o: Failed reset at end of transaction (%04x)\n", + temp); + } + printk + ("i2c-amd756.o: Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); +#endif + + return result; +} + +/* Return -1 on error. */ +s32 amd756_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data * data) +{ + int i, len; + + /** TODO: Should I supporte the 10-bit transfers? */ + switch (size) { + case I2C_SMBUS_PROC_CALL: + printk + ("i2c-amd756.o: I2C_SMBUS_PROC_CALL not supported!\n"); + /* TODO: Well... It is supported, I'm just not sure what to do here... */ + return -1; + case I2C_SMBUS_QUICK: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + size = AMD756_QUICK; + break; + case I2C_SMBUS_BYTE: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + /* TODO: Why only during write? */ + if (read_write == I2C_SMBUS_WRITE) + outb_p(command, SMB_HOST_COMMAND); + size = AMD756_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) + outw_p(data->byte, SMB_HOST_DATA); + size = AMD756_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) + outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */ + size = AMD756_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMB_HOST_ADDRESS); + outb_p(command, SMB_HOST_COMMAND); + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + if (len < 0) + len = 0; + if (len > 32) + len = 32; + outw_p(len, SMB_HOST_DATA); + /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ + for (i = 1; i <= len; i++) + outb_p(data->block[i], + SMB_HOST_BLOCK_DATA); + } + size = AMD756_BLOCK_DATA; + break; + } + + /* How about enabling interrupts... */ + outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE); + + if (amd756_transaction()) /* Error in transaction */ + return -1; + + if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK)) + return 0; + + + switch (size) { + case AMD756_BYTE: + data->byte = inw_p(SMB_HOST_DATA); + break; + case AMD756_BYTE_DATA: + data->byte = inw_p(SMB_HOST_DATA); + break; + case AMD756_WORD_DATA: + data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */ + break; + case AMD756_BLOCK_DATA: + data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f; + if(data->block[0] > 32) + data->block[0] = 32; + /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ + for (i = 1; i <= data->block[0]; i++) + data->block[i] = inb_p(SMB_HOST_BLOCK_DATA); + break; + } + + return 0; +} + +void amd756_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void amd756_dec(struct i2c_adapter *adapter) +{ + + MOD_DEC_USE_COUNT; +} + +u32 amd756_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL; +} + +int __init i2c_amd756_init(void) +{ + int res; +#ifdef DEBUG +/* PE- It might be good to make this a permanent part of the code! */ + if (amd756_initialized) { + printk + ("i2c-amd756.o: Oops, amd756_init called a second time!\n"); + return -EBUSY; + } +#endif + amd756_initialized = 0; + if ((res = amd756_setup())) { + printk + ("i2c-amd756.o: AMD756 or compatible device not detected, module not inserted.\n"); + amd756_cleanup(); + return res; + } + amd756_initialized++; + sprintf(amd756_adapter.name, "SMBus %s adapter at %04x", + amd756_sd->name, amd756_smba); + if ((res = i2c_add_adapter(&amd756_adapter))) { + printk + ("i2c-amd756.o: Adapter registration failed, module not inserted.\n"); + amd756_cleanup(); + return res; + } + amd756_initialized++; + printk("i2c-amd756.o: %s bus detected and initialized\n", + amd756_sd->name); + return 0; +} + +void __exit i2c_amd756_exit(void) +{ + amd756_cleanup(); +} + +static int amd756_cleanup(void) +{ + int res; + if (amd756_initialized >= 2) { + if ((res = i2c_del_adapter(&amd756_adapter))) { + printk + ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n"); + return res; + } else + amd756_initialized--; + } + if (amd756_initialized >= 1) { + release_region(amd756_smba, SMB_IOSIZE); + amd756_initialized--; + } + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE + +MODULE_AUTHOR("Merlin Hughes "); +MODULE_DESCRIPTION("AMD756/766/768/nVidia nForce SMBus driver"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#endif /* MODULE */ + +module_init(i2c_amd756_init) +module_exit(i2c_amd756_exit) diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c new file mode 100644 index 000000000000..ac2f741d3843 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -0,0 +1,425 @@ +/* + * SMBus 2.0 driver for AMD-8111 IO-Hub. + * + * Copyright (c) 2002 Vojtech Pavlik + * + * 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 version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Vojtech Pavlik "); +MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver"); + +struct amd_smbus { + struct pci_dev *dev; + struct i2c_adapter adapter; + int base; + int size; +}; + +/* + * AMD PCI control registers definitions. + */ + +#define AMD_PCI_MISC 0x48 + +#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */ +#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */ +#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */ + +/* + * ACPI 2.0 chapter 13 PCI interface definitions. + */ + +#define AMD_EC_DATA 0x00 /* data register */ +#define AMD_EC_SC 0x04 /* status of controller */ +#define AMD_EC_CMD 0x04 /* command register */ +#define AMD_EC_ICR 0x08 /* interrupt control register */ + +#define AMD_EC_SC_SMI 0x04 /* smi event pending */ +#define AMD_EC_SC_SCI 0x02 /* sci event pending */ +#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */ +#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */ +#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */ +#define AMD_EC_SC_OBF 0x01 /* data ready for host */ + +#define AMD_EC_CMD_RD 0x80 /* read EC */ +#define AMD_EC_CMD_WR 0x81 /* write EC */ +#define AMD_EC_CMD_BE 0x82 /* enable burst mode */ +#define AMD_EC_CMD_BD 0x83 /* disable burst mode */ +#define AMD_EC_CMD_QR 0x84 /* query EC */ + +/* + * ACPI 2.0 chapter 13 access of registers of the EC + */ + +unsigned int amd_ec_wait_write(struct amd_smbus *smbus) +{ + int timeout = 500; + + while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF)) + udelay(1); + + if (!timeout) { + printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n"); + return -1; + } + + return 0; +} + +unsigned int amd_ec_wait_read(struct amd_smbus *smbus) +{ + int timeout = 500; + + while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF)) + udelay(1); + + if (!timeout) { + printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n"); + return -1; + } + + return 0; +} + +unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) +{ + if (amd_ec_wait_write(smbus)) + return -1; + outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(address, smbus->base + AMD_EC_DATA); + + if (amd_ec_wait_read(smbus)) + return -1; + *data = inb(smbus->base + AMD_EC_DATA); + + return 0; +} + +unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) +{ + if (amd_ec_wait_write(smbus)) + return -1; + outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(address, smbus->base + AMD_EC_DATA); + + if (amd_ec_wait_write(smbus)) + return -1; + outb(data, smbus->base + AMD_EC_DATA); + + return 0; +} + +/* + * ACPI 2.0 chapter 13 SMBus 2.0 EC register model + */ + +#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */ +#define AMD_SMB_STS 0x01 /* status */ +#define AMD_SMB_ADDR 0x02 /* address */ +#define AMD_SMB_CMD 0x03 /* command */ +#define AMD_SMB_DATA 0x04 /* 32 data registers */ +#define AMD_SMB_BCNT 0x24 /* number of data bytes */ +#define AMD_SMB_ALRM_A 0x25 /* alarm address */ +#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */ + +#define AMD_SMB_STS_DONE 0x80 +#define AMD_SMB_STS_ALRM 0x40 +#define AMD_SMB_STS_RES 0x20 +#define AMD_SMB_STS_STATUS 0x1f + +#define AMD_SMB_STATUS_OK 0x00 +#define AMD_SMB_STATUS_FAIL 0x07 +#define AMD_SMB_STATUS_DNAK 0x10 +#define AMD_SMB_STATUS_DERR 0x11 +#define AMD_SMB_STATUS_CMD_DENY 0x12 +#define AMD_SMB_STATUS_UNKNOWN 0x13 +#define AMD_SMB_STATUS_ACC_DENY 0x17 +#define AMD_SMB_STATUS_TIMEOUT 0x18 +#define AMD_SMB_STATUS_NOTSUP 0x19 +#define AMD_SMB_STATUS_BUSY 0x1A +#define AMD_SMB_STATUS_PEC 0x1F + +#define AMD_SMB_PRTCL_WRITE 0x00 +#define AMD_SMB_PRTCL_READ 0x01 +#define AMD_SMB_PRTCL_QUICK 0x02 +#define AMD_SMB_PRTCL_BYTE 0x04 +#define AMD_SMB_PRTCL_BYTE_DATA 0x06 +#define AMD_SMB_PRTCL_WORD_DATA 0x08 +#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a +#define AMD_SMB_PRTCL_PROC_CALL 0x0c +#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d +#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a +#define AMD_SMB_PRTCL_PEC 0x80 + + +s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, union i2c_smbus_data * data) +{ + struct amd_smbus *smbus = adap->algo_data; + unsigned char protocol, len, pec, temp[2]; + int i; + + protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; + pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0; + + switch (size) { + + case I2C_SMBUS_QUICK: + protocol |= AMD_SMB_PRTCL_QUICK; + read_write = I2C_SMBUS_WRITE; + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_DATA, data->byte); + protocol |= AMD_SMB_PRTCL_BYTE; + break; + + case I2C_SMBUS_BYTE_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) + amd_ec_write(smbus, AMD_SMB_DATA, data->byte); + protocol |= AMD_SMB_PRTCL_BYTE_DATA; + break; + + case I2C_SMBUS_WORD_DATA_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_WORD_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + } + protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; + break; + + case I2C_SMBUS_BLOCK_DATA_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_BLOCK_DATA: + amd_ec_write(smbus, AMD_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + len = min_t(u8, data->block[0], 32); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + } + protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; + break; + + case I2C_SMBUS_I2C_BLOCK_DATA: + len = min_t(u8, data->block[0], 32); + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + if (read_write == I2C_SMBUS_WRITE) + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; + break; + + case I2C_SMBUS_PROC_CALL_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_PROC_CALL: + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + protocol = AMD_SMB_PRTCL_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + protocol |= AMD_SMB_PRTCL_PEC; + case I2C_SMBUS_BLOCK_PROC_CALL: + protocol |= pec; + len = min_t(u8, data->block[0], 31); + amd_ec_write(smbus, AMD_SMB_CMD, command); + amd_ec_write(smbus, AMD_SMB_BCNT, len); + for (i = 0; i < len; i++) + amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + default: + printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size); + return -1; + } + + amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1); + amd_ec_write(smbus, AMD_SMB_PRTCL, protocol); + + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + + if (~temp[0] & AMD_SMB_STS_DONE) { + udelay(500); + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + } + + if (~temp[0] & AMD_SMB_STS_DONE) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/100); + amd_ec_read(smbus, AMD_SMB_STS, temp + 0); + } + + if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS)) + return -1; + + if (read_write == I2C_SMBUS_WRITE) + return 0; + + switch (size) { + + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); + break; + + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_WORD_DATA_PEC: + case I2C_SMBUS_PROC_CALL: + case I2C_SMBUS_PROC_CALL_PEC: + amd_ec_read(smbus, AMD_SMB_DATA, temp + 0); + amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1); + data->word = (temp[1] << 8) | temp[0]; + break; + + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_DATA_PEC: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + amd_ec_read(smbus, AMD_SMB_BCNT, &len); + len = min_t(u8, len, 32); + case I2C_SMBUS_I2C_BLOCK_DATA: + for (i = 0; i < len; i++) + amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1); + data->block[0] = len; + break; + } + + return 0; +} + +void amd8111_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +void amd8111_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +u32 amd8111_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WORD_DATA_PEC | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA_PEC | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PROC_CALL_PEC | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; +} + +static struct i2c_algorithm smbus_algorithm = { + .name = "Non-I2C SMBus 2.0 adapter", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = amd8111_access, + .functionality = amd8111_func, +}; + +static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct amd_smbus *smbus; + + if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) + return -1; + + if (!(smbus = (void*)kmalloc(sizeof(struct amd_smbus), GFP_KERNEL))) + return -1; + memset(smbus, 0, sizeof(struct amd_smbus)); + + pci_set_drvdata(dev, smbus); + smbus->dev = dev; + smbus->base = pci_resource_start(dev, 0); + smbus->size = pci_resource_len(dev, 0); + + if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) { + kfree(smbus); + return -1; + } + + sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base); + smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; + smbus->adapter.algo = &smbus_algorithm; + smbus->adapter.algo_data = smbus; + smbus->adapter.inc_use = amd8111_inc; + smbus->adapter.dec_use = amd8111_dec; + + if (i2c_add_adapter(&smbus->adapter)) { + printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n"); + release_region(smbus->base, smbus->size); + kfree(smbus); + return -1; + } + + pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); + + printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base); + return 0; +} + +static void __devexit amd8111_remove(struct pci_dev *dev) +{ + struct amd_smbus *smbus = (void*) pci_get_drvdata(dev); + if (i2c_del_adapter(&smbus->adapter)) { + printk(KERN_WARNING "i2c-amd8111.c: Failed to unregister adapter.\n"); + return; + } + release_region(smbus->base, smbus->size); + kfree(smbus); +} + +static struct pci_device_id amd8111_id_table[] __devinitdata = +{{ 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 }}; + + +static struct pci_driver amd8111_driver = { + .name = "amd8111 smbus 2.0", + .id_table = amd8111_id_table, + .probe = amd8111_probe, + .remove = __devexit_p(amd8111_remove), +}; + +int __init amd8111_init(void) +{ + return pci_module_init(&amd8111_driver); +} + +void __exit amd8111_exit(void) +{ + pci_unregister_driver(&amd8111_driver); +} + +module_init(amd8111_init); +module_exit(amd8111_exit); diff --git a/drivers/i2c/busses/i2c-mainboard.c b/drivers/i2c/busses/i2c-mainboard.c new file mode 100644 index 000000000000..5c58598bd399 --- /dev/null +++ b/drivers/i2c/busses/i2c-mainboard.c @@ -0,0 +1,34 @@ +/* + i2c-mainboard.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Not configurable as a module */ + +#include + +extern int i2c_amd756_init(void); + +int __init i2c_mainboard_init_all(void) +{ +#ifdef CONFIG_I2C_AMD756 + i2c_amd756_init(); +#endif + + return 0; +} diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig new file mode 100644 index 000000000000..19ade539d2ac --- /dev/null +++ b/drivers/i2c/chips/Kconfig @@ -0,0 +1,54 @@ +# +# Sensor device configuration +# All depend on EXPERIMENTAL, I2C and I2C_PROC. +# + +menu "I2C Hardware Sensors Chip support" + +config SENSORS + bool "Hardware sensors chip support" + depends on EXPERIMENTAL && I2C && I2C_PROC + help + Many modern mainboards have some kind of I2C interface integrated. + This is often in the form of a SMBus, or System Management Bus, which + is basically the same as I2C but which uses only a subset of the I2C + protocol. + + You will also want the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config SENSORS_ADM1021 + tristate " Analog Devices ADM1021 and compatibles" + depends on SENSORS + help + If you say yes here you get support for Analog Devices ADM1021 + and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, + Genesys Logic GL523SM, National Semi LM84, TI THMC10, + and the XEON processor built-in sensor. This can also + be built as a module which can be inserted and removed while the + kernel is running. + + The module will be called adm1021.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config SENSORS_LM75 + tristate " National Semiconductors LM75 and compatibles" + depends on SENSORS + help + If you say yes here you get support for National Semiconductor LM75 + sensor chips and clones: Dallas Semi DS75 and DS1775, TelCon + TCN75, and National Semi LM77. This can also be built as a module + which can be inserted and removed while the kernel is running. + + The module will be called lm75.o. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +endmenu + diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile new file mode 100644 index 000000000000..0bb64d68a61e --- /dev/null +++ b/drivers/i2c/chips/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the kernel hardware sensors chip drivers. +# + +obj-$(CONFIG_SENSORS) += sensors.o +obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o +obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c new file mode 100644 index 000000000000..54a76b9a0309 --- /dev/null +++ b/drivers/i2c/chips/adm1021.c @@ -0,0 +1,633 @@ +/* + adm1021.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, + 0x4c, 0x4e, SENSORS_I2C_END +}; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); + +/* adm1021 constants specified below */ + +/* The adm1021 registers */ +/* Read-only */ +#define ADM1021_REG_TEMP 0x00 +#define ADM1021_REG_REMOTE_TEMP 0x01 +#define ADM1021_REG_STATUS 0x02 +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* These use different addresses for reading/writing */ +#define ADM1021_REG_CONFIG_R 0x03 +#define ADM1021_REG_CONFIG_W 0x09 +#define ADM1021_REG_CONV_RATE_R 0x04 +#define ADM1021_REG_CONV_RATE_W 0x0A +/* These are for the ADM1023's additional precision on the remote temp sensor */ +#define ADM1021_REG_REM_TEMP_PREC 0x010 +#define ADM1021_REG_REM_OFFSET 0x011 +#define ADM1021_REG_REM_OFFSET_PREC 0x012 +#define ADM1021_REG_REM_TOS_PREC 0x013 +#define ADM1021_REG_REM_THYST_PREC 0x014 +/* limits */ +#define ADM1021_REG_TOS_R 0x05 +#define ADM1021_REG_TOS_W 0x0B +#define ADM1021_REG_REMOTE_TOS_R 0x07 +#define ADM1021_REG_REMOTE_TOS_W 0x0D +#define ADM1021_REG_THYST_R 0x06 +#define ADM1021_REG_THYST_W 0x0C +#define ADM1021_REG_REMOTE_THYST_R 0x08 +#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* write-only */ +#define ADM1021_REG_ONESHOT 0x0F + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +/* Conversions note: 1021 uses normal integer signed-byte format*/ +#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) + +/* Initial values */ + +/* Note: Eventhough I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actuall triggers an alarm instead of +clearing it. Weird, ey? --Phil */ +#define adm1021_INIT_TOS 60 +#define adm1021_INIT_THYST 20 +#define adm1021_INIT_REMOTE_TOS 60 +#define adm1021_INIT_REMOTE_THYST 20 + +/* Each client has this additional data */ +struct adm1021_data { + int sysctl_id; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 temp, temp_os, temp_hyst; /* Register values */ + u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; + /* Special values for ADM1023 only */ + u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, + remote_temp_offset, remote_temp_offset_prec; +}; + +int __init sensors_adm1021_init(void); +void __exit sensors_adm1021_exit(void); +static int adm1021_cleanup(void); + +static int adm1021_attach_adapter(struct i2c_adapter *adapter); +static int adm1021_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static void adm1021_init_client(struct i2c_client *client); +static int adm1021_detach_client(struct i2c_client *client); +static int adm1021_command(struct i2c_client *client, unsigned int cmd, + void *arg); +static void adm1021_inc_use(struct i2c_client *client); +static void adm1021_dec_use(struct i2c_client *client); +static int adm1021_read_value(struct i2c_client *client, u8 reg); +static int adm1021_write_value(struct i2c_client *client, u8 reg, + u16 value); +static void adm1021_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, + long *results); +static void adm1021_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_die_code(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void adm1021_update_client(struct i2c_client *client); + +/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ +static int read_only = 0; + + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1021_driver = { + /* name */ "ADM1021, MAX1617 sensor driver", + /* id */ I2C_DRIVERID_ADM1021, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &adm1021_attach_adapter, + /* detach_client */ &adm1021_detach_client, + /* command */ &adm1021_command, + /* inc_use */ &adm1021_inc_use, + /* dec_use */ &adm1021_dec_use +}; + +/* These files are created for each detected adm1021. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ +static ctl_table adm1021_dir_table_template[] = { + {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_temp}, + {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_remote_temp}, + {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_die_code}, + {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_alarms}, + {0} +}; + +static ctl_table adm1021_max_dir_table_template[] = { + {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_temp}, + {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_remote_temp}, + {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &adm1021_alarms}, + {0} +}; + +/* Used by init/cleanup */ +static int __initdata adm1021_initialized = 0; + +/* I choose here for semi-static allocation. Complete dynamic + allocation could also be used; the code needed for this would probably + take more memory than the datastructure takes now. */ +static int adm1021_id = 0; + +int adm1021_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, adm1021_detect); +} + +static int adm1021_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i; + struct i2c_client *new_client; + struct adm1021_data *data; + int err = 0; + const char *type_name = ""; + const char *client_name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + printk + ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1021_{read,write}_value. */ + + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct adm1021_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + + data = (struct adm1021_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &adm1021_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ( + (adm1021_read_value(new_client, ADM1021_REG_STATUS) & + 0x03) != 0x00) + goto error1; + } + + /* Determine the chip type. */ + + if (kind <= 0) { + i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + if (i == 0x41) + if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + kind = adm1023; + else + kind = adm1021; + else if (i == 0x49) + kind = thmc10; + else if (i == 0x23) + kind = gl523sm; + else if ((i == 0x4d) && + (adm1021_read_value + (new_client, ADM1021_REG_DEV_ID) == 0x01)) + kind = max1617a; + /* LM84 Mfr ID in a different place */ + else + if (adm1021_read_value + (new_client, ADM1021_REG_CONV_RATE_R) == 0x00) + kind = lm84; + else if (i == 0x54) + kind = mc1066; + else + kind = max1617; + } + + if (kind == max1617) { + type_name = "max1617"; + client_name = "MAX1617 chip"; + } else if (kind == max1617a) { + type_name = "max1617a"; + client_name = "MAX1617A chip"; + } else if (kind == adm1021) { + type_name = "adm1021"; + client_name = "ADM1021 chip"; + } else if (kind == adm1023) { + type_name = "adm1023"; + client_name = "ADM1023 chip"; + } else if (kind == thmc10) { + type_name = "thmc10"; + client_name = "THMC10 chip"; + } else if (kind == lm84) { + type_name = "lm84"; + client_name = "LM84 chip"; + } else if (kind == gl523sm) { + type_name = "gl523sm"; + client_name = "GL523SM chip"; + } else if (kind == mc1066) { + type_name = "mc1066"; + client_name = "MC1066 chip"; + } else { +#ifdef DEBUG + printk("adm1021.o: Internal error: unknown kind (%d)?!?", + kind); +#endif + goto error1; + } + + /* Fill in the remaining client fields and put it into the global list */ + strcpy(new_client->name, client_name); + data->type = kind; + + new_client->id = adm1021_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error3; + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, + type_name, + data->type == + adm1021 ? + adm1021_dir_table_template : + adm1021_max_dir_table_template, + THIS_MODULE)) < 0) { + err = i; + goto error4; + } + data->sysctl_id = i; + + /* Initialize the ADM1021 chip */ + adm1021_init_client(new_client); + return 0; + + error4: + i2c_detach_client(new_client); + error3: + error1: + kfree(new_client); + error0: + return err; +} + +void adm1021_init_client(struct i2c_client *client) +{ + /* Initialize the adm1021 chip */ + adm1021_write_value(client, ADM1021_REG_TOS_W, + TEMP_TO_REG(adm1021_INIT_TOS)); + adm1021_write_value(client, ADM1021_REG_THYST_W, + TEMP_TO_REG(adm1021_INIT_THYST)); + adm1021_write_value(client, ADM1021_REG_REMOTE_TOS_W, + TEMP_TO_REG(adm1021_INIT_REMOTE_TOS)); + adm1021_write_value(client, ADM1021_REG_REMOTE_THYST_W, + TEMP_TO_REG(adm1021_INIT_REMOTE_THYST)); + /* Enable ADC and disable suspend mode */ + adm1021_write_value(client, ADM1021_REG_CONFIG_W, 0); + /* Set Conversion rate to 1/sec (this can be tinkered with) */ + adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); +} + +int adm1021_detach_client(struct i2c_client *client) +{ + + int err; + + i2c_deregister_entry(((struct adm1021_data *) (client->data))-> + sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk + ("adm1021.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; + +} + + +/* No commands defined yet */ +int adm1021_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + return 0; +} + +void adm1021_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +void adm1021_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} + +/* All registers are byte-sized */ +int adm1021_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (read_only > 0) + return 0; + + return i2c_smbus_write_byte_data(client, reg, value); +} + +void adm1021_update_client(struct i2c_client *client) +{ + struct adm1021_data *data = client->data; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + +#ifdef DEBUG + printk("Starting adm1021 update\n"); +#endif + + data->temp = adm1021_read_value(client, ADM1021_REG_TEMP); + data->temp_os = + adm1021_read_value(client, ADM1021_REG_TOS_R); + data->temp_hyst = + adm1021_read_value(client, ADM1021_REG_THYST_R); + data->remote_temp = + adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); + data->remote_temp_os = + adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); + data->remote_temp_hyst = + adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); + data->alarms = + adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec; + if (data->type == adm1021) + data->die_code = + adm1021_read_value(client, + ADM1021_REG_DIE_CODE); + if (data->type == adm1023) { + data->remote_temp_prec = + adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = + adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = + adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); + data->remote_temp_offset = + adm1021_read_value(client, ADM1021_REG_REM_OFFSET); + data->remote_temp_offset_prec = + adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_os); + results[1] = TEMP_FROM_REG(data->temp_hyst); + results[2] = TEMP_FROM_REG(data->temp); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->temp_os = TEMP_TO_REG(results[0]); + adm1021_write_value(client, ADM1021_REG_TOS_W, + data->temp_os); + } + if (*nrels_mag >= 2) { + data->temp_hyst = TEMP_TO_REG(results[1]); + adm1021_write_value(client, ADM1021_REG_THYST_W, + data->temp_hyst); + } + } +} + +void adm1021_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ +int prec=0; + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + if (data->type == adm1023) { *nrels_mag = 3; } + else { *nrels_mag = 0; } + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = TEMP_FROM_REG(data->remote_temp_os); + results[1] = TEMP_FROM_REG(data->remote_temp_hyst); + results[2] = TEMP_FROM_REG(data->remote_temp); + if (data->type == adm1023) { + results[0]=results[0]*1000 + + ((data->remote_temp_os_prec >> 5) * 125); + results[1]=results[1]*1000 + + ((data->remote_temp_hyst_prec >> 5) * 125); + results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) + + ((data->remote_temp_offset_prec >> 5) * 125); + results[3]=TEMP_FROM_REG(data->remote_temp)*1000 + + ((data->remote_temp_prec >> 5) * 125); + *nrels_mag = 4; + } else { + *nrels_mag = 3; + } + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + if (data->type == adm1023) { + prec=((results[0]-((results[0]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_TOS_PREC, + prec); + results[0]=results[0]/1000; + data->remote_temp_os_prec=prec; + } + data->remote_temp_os = TEMP_TO_REG(results[0]); + adm1021_write_value(client, + ADM1021_REG_REMOTE_TOS_W, + data->remote_temp_os); + } + if (*nrels_mag >= 2) { + if (data->type == adm1023) { + prec=((results[1]-((results[1]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_THYST_PREC, + prec); + results[1]=results[1]/1000; + data->remote_temp_hyst_prec=prec; + } + data->remote_temp_hyst = TEMP_TO_REG(results[1]); + adm1021_write_value(client, + ADM1021_REG_REMOTE_THYST_W, + data->remote_temp_hyst); + } + if (*nrels_mag >= 3) { + if (data->type == adm1023) { + prec=((results[2]-((results[2]/1000)*1000))/125)<<5; + adm1021_write_value(client, + ADM1021_REG_REM_OFFSET_PREC, + prec); + results[2]=results[2]/1000; + data->remote_temp_offset_prec=prec; + data->remote_temp_offset=results[2]; + adm1021_write_value(client, + ADM1021_REG_REM_OFFSET, + data->remote_temp_offset); + } + } + } +} + +void adm1021_die_code(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = data->die_code; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + /* Can't write to it */ + } +} + +void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct adm1021_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + adm1021_update_client(client); + results[0] = data->alarms; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + /* Can't write to it */ + } +} + +int __init sensors_adm1021_init(void) +{ + int res; + + printk("adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); + adm1021_initialized = 0; + if ((res = i2c_add_driver(&adm1021_driver))) { + printk + ("adm1021.o: Driver registration failed, module not inserted.\n"); + adm1021_cleanup(); + return res; + } + adm1021_initialized++; + return 0; +} + +void __exit sensors_adm1021_exit(void) +{ + adm1021_cleanup(); +} + +static int adm1021_cleanup(void) +{ + int res; + + if (adm1021_initialized >= 1) { + if ((res = i2c_del_driver(&adm1021_driver))) { + printk + ("adm1021.o: Driver deregistration failed, module not removed.\n"); + return res; + } + adm1021_initialized--; + } + + return 0; +} + +MODULE_AUTHOR + ("Frodo Looijaard and Philip Edelbrock "); +MODULE_DESCRIPTION("adm1021 driver"); + +MODULE_PARM(read_only, "i"); +MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); + +module_init(sensors_adm1021_init) +module_exit(sensors_adm1021_exit) diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c new file mode 100644 index 000000000000..f7a516b82703 --- /dev/null +++ b/drivers/i2c/chips/lm75.c @@ -0,0 +1,403 @@ +/* + lm75.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm75); + +/* Many LM75 constants specified below */ + +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_TEMP_HYST 0x02 +#define LM75_REG_TEMP_OS 0x03 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | ((val & 0x8000)?-256:0)) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0?(0x200+((val)/5))<<7:(((val) + 2) / 5) << 7),0,0xffff)) + +/* Initial values */ +#define LM75_INIT_TEMP_OS 600 +#define LM75_INIT_TEMP_HYST 500 + +/* Each client has this additional data */ +struct lm75_data { + int sysctl_id; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 temp, temp_os, temp_hyst; /* Register values */ +}; + +int __init sensors_lm75_init(void); +void __exit sensors_lm75_exit(void); +static int lm75_cleanup(void); + +static int lm75_attach_adapter(struct i2c_adapter *adapter); +static int lm75_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static void lm75_init_client(struct i2c_client *client); +static int lm75_detach_client(struct i2c_client *client); +static int lm75_command(struct i2c_client *client, unsigned int cmd, + void *arg); +static void lm75_inc_use(struct i2c_client *client); +static void lm75_dec_use(struct i2c_client *client); +static u16 swap_bytes(u16 val); +static int lm75_read_value(struct i2c_client *client, u8 reg); +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); +static void lm75_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void lm75_update_client(struct i2c_client *client); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm75_driver = { + /* name */ "LM75 sensor chip driver", + /* id */ I2C_DRIVERID_LM75, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &lm75_attach_adapter, + /* detach_client */ &lm75_detach_client, + /* command */ &lm75_command, + /* inc_use */ &lm75_inc_use, + /* dec_use */ &lm75_dec_use +}; + +/* These files are created for each detected LM75. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ +static ctl_table lm75_dir_table_template[] = { + {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm75_temp}, + {0} +}; + +/* Used by init/cleanup */ +static int __initdata lm75_initialized = 0; + +static int lm75_id = 0; + +int lm75_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, lm75_detect); +} + +/* This function is called by i2c_detect */ +int lm75_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i, cur, conf, hyst, os; + struct i2c_client *new_client; + struct lm75_data *data; + int err = 0; + const char *type_name, *client_name; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + printk + ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm75_{read,write}_value. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct lm75_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + + data = (struct lm75_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &lm75_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. It is lousy. */ + if (kind < 0) { + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + os = i2c_smbus_read_word_data(new_client, 3); + for (i = 0; i <= 0x1f; i++) + if ( + (i2c_smbus_read_byte_data + (new_client, i * 8 + 1) != conf) + || + (i2c_smbus_read_word_data + (new_client, i * 8 + 2) != hyst) + || + (i2c_smbus_read_word_data + (new_client, i * 8 + 3) != os)) + goto error1; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm75; + + if (kind == lm75) { + type_name = "lm75"; + client_name = "LM75 chip"; + } else { +#ifdef DEBUG + printk("lm75.o: Internal error: unknown kind (%d)?!?", + kind); +#endif + goto error1; + } + + /* Fill in the remaining client fields and put it into the global list */ + strcpy(new_client->name, client_name); + + new_client->id = lm75_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error3; + + /* Register a new directory entry with module sensors */ + if ((i = i2c_register_entry(new_client, type_name, + lm75_dir_table_template, + THIS_MODULE)) < 0) { + err = i; + goto error4; + } + data->sysctl_id = i; + + lm75_init_client(new_client); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + error4: + i2c_detach_client(new_client); + error3: + error1: + kfree(new_client); + error0: + return err; +} + +int lm75_detach_client(struct i2c_client *client) +{ + int err; + +#ifdef MODULE + if (MOD_IN_USE) + return -EBUSY; +#endif + + i2c_deregister_entry(((struct lm75_data *) (client->data))-> + sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk + ("lm75.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +int lm75_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + return 0; +} + +void lm75_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +void lm75_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} + +u16 swap_bytes(u16 val) +{ + return (val >> 8) | (val << 8); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +int lm75_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swap_bytes(i2c_smbus_read_word_data(client, reg)); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, + swap_bytes(value)); +} + +void lm75_init_client(struct i2c_client *client) +{ + /* Initialize the LM75 chip */ + lm75_write_value(client, LM75_REG_TEMP_OS, + TEMP_TO_REG(LM75_INIT_TEMP_OS)); + lm75_write_value(client, LM75_REG_TEMP_HYST, + TEMP_TO_REG(LM75_INIT_TEMP_HYST)); + lm75_write_value(client, LM75_REG_CONF, 0); +} + +void lm75_update_client(struct i2c_client *client) +{ + struct lm75_data *data = client->data; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + +#ifdef DEBUG + printk("Starting lm75 update\n"); +#endif + + data->temp = lm75_read_value(client, LM75_REG_TEMP); + data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); + data->temp_hyst = + lm75_read_value(client, LM75_REG_TEMP_HYST); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +void lm75_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm75_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm75_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_os); + results[1] = TEMP_FROM_REG(data->temp_hyst); + results[2] = TEMP_FROM_REG(data->temp); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->temp_os = TEMP_TO_REG(results[0]); + lm75_write_value(client, LM75_REG_TEMP_OS, + data->temp_os); + } + if (*nrels_mag >= 2) { + data->temp_hyst = TEMP_TO_REG(results[1]); + lm75_write_value(client, LM75_REG_TEMP_HYST, + data->temp_hyst); + } + } +} + +int __init sensors_lm75_init(void) +{ + int res; + + printk("lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); + lm75_initialized = 0; + if ((res = i2c_add_driver(&lm75_driver))) { + printk + ("lm75.o: Driver registration failed, module not inserted.\n"); + lm75_cleanup(); + return res; + } + lm75_initialized++; + return 0; +} + +void __exit sensors_lm75_exit(void) +{ + lm75_cleanup(); +} + +static int lm75_cleanup(void) +{ + int res; + + if (lm75_initialized >= 1) { + if ((res = i2c_del_driver(&lm75_driver))) { + printk + ("lm75.o: Driver deregistration failed, module not removed.\n"); + return res; + } + lm75_initialized--; + } + + return 0; +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM75 driver"); + +module_init(sensors_lm75_init); +module_exit(sensors_lm75_exit); diff --git a/drivers/i2c/chips/sensors.c b/drivers/i2c/chips/sensors.c new file mode 100644 index 000000000000..0733c474753b --- /dev/null +++ b/drivers/i2c/chips/sensors.c @@ -0,0 +1,37 @@ +/* + sensors.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Not configurable as a module */ + +#include + +extern int sensors_adm1021_init(void); +extern int sensors_lm75_init(void); + +int __init sensors_init_all(void) +{ +#ifdef CONFIG_SENSORS_ADM1021 + sensors_adm1021_init(); +#endif +#ifdef CONFIG_SENSORS_LM75 + sensors_lm75_init(); +#endif + return 0; +} diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0716d42479f7..01af09b5120f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -21,7 +21,7 @@ All SMBus-related things are written by Frodo Looijaard SMBus 2.0 support by Mark Studebaker */ -/* $Id: i2c-core.c,v 1.86 2002/09/12 06:47:26 ac9410 Exp $ */ +/* $Id: i2c-core.c,v 1.89 2002/11/03 16:47:16 mds Exp $ */ #include #include @@ -77,7 +77,8 @@ static int i2c_debug; #ifdef CONFIG_PROC_FS -static int i2cproc_init(void); +int __init i2cproc_init(void); +void __exit i2cproc_exit(void); static int i2cproc_cleanup(void); static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, @@ -1332,15 +1333,15 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; } else { - msg[0].len = data->block[0] + 2; - if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 2) { + msg[0].len = data->block[0] + 1; + if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { printk("i2c-core.o: i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); return -1; } - for (i = 0; i < data->block[0]; i++) - msgbuf0[i] = data->block[i+1]; + for (i = 1; i <= data->block[0]; i++) + msgbuf0[i] = data->block[i]; } break; default: @@ -1456,7 +1457,7 @@ static int __init i2c_init(void) return 0; } -static void __exit i2c_exit(void) +void __exit i2c_exit(void) { i2cproc_cleanup(); } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 73c20b3069be..a2c539a5d269 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,7 +28,7 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.46 2002/07/06 02:07:39 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.48 2002/10/01 14:10:04 ac9410 Exp $ */ #include #include @@ -48,6 +48,10 @@ #include #include +int __init i2c_dev_init(void); +void __exit i2c_dev_exit(void); +static int dev_cleanup(void); + /* struct file_operations changed too often in the 2.1 series for nice code */ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, @@ -433,7 +437,7 @@ static int i2cdev_command(struct i2c_client *client, unsigned int cmd, return -1; } -static void i2cdev_cleanup(void) +static int dev_cleanup(void) { int res; @@ -467,6 +471,11 @@ int __init i2c_dev_init(void) return 0; } +void __exit i2c_dev_exit(void) +{ + dev_cleanup(); +} + EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); @@ -474,4 +483,4 @@ MODULE_DESCRIPTION("I2C /dev entries driver"); MODULE_LICENSE("GPL"); module_init(i2c_dev_init); -module_exit(i2cdev_cleanup); +module_exit(i2c_dev_exit); diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c index 6c6d4903a023..2f26eab8d882 100644 --- a/drivers/i2c/i2c-proc.c +++ b/drivers/i2c/i2c-proc.c @@ -40,6 +40,10 @@ #define THIS_MODULE NULL #endif +int __init sensors_init(void); +void __exit i2c_proc_exit(void); +static int proc_cleanup(void); + static int i2c_create_name(char **name, const char *prefix, struct i2c_adapter *adapter, int addr); static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, @@ -56,6 +60,7 @@ static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, #define SENSORS_ENTRY_MAX 20 static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; +static unsigned short i2c_inodes[SENSORS_ENTRY_MAX]; static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; @@ -186,6 +191,8 @@ int i2c_register_entry(struct i2c_client *client, const char *prefix, return id; } #endif /* DEBUG */ + i2c_inodes[id - 256] = + new_header->ctl_table->child->child->de->low_ino; new_header->ctl_table->child->child->de->owner = controlling_mod; return id; @@ -208,6 +215,49 @@ void i2c_deregister_entry(int id) } } +/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o + impossible if some process still uses it or some file in it */ +void i2c_fill_inode(struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading + the corresponding module impossible if some process still uses it or + some file in it */ +void i2c_dir_fill_inode(struct inode *inode, int fill) +{ + int i; + struct i2c_client *client; + +#ifdef DEBUG + if (!inode) { + printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n"); + return; + } +#endif /* def DEBUG */ + + for (i = 0; i < SENSORS_ENTRY_MAX; i++) + if (i2c_clients[i] + && (i2c_inodes[i] == inode->i_ino)) break; +#ifdef DEBUG + if (i == SENSORS_ENTRY_MAX) { + printk + (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", + inode->i_ino); + return; + } +#endif /* def DEBUG */ + client = i2c_clients[i]; + if (fill) + client->driver->inc_use(client); + else + client->driver->dec_use(client); +} + int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp) { @@ -813,12 +863,18 @@ int __init sensors_init(void) return 0; } -static void __exit i2c_cleanup(void) +void __exit i2c_proc_exit(void) +{ + proc_cleanup(); +} + +static int proc_cleanup(void) { if (i2c_initialized >= 1) { unregister_sysctl_table(i2c_proc_header); i2c_initialized--; } + return 0; } EXPORT_SYMBOL(i2c_deregister_entry); @@ -832,4 +888,4 @@ MODULE_DESCRIPTION("i2c-proc driver"); MODULE_LICENSE("GPL"); module_init(sensors_init); -module_exit(i2c_cleanup); +module_exit(i2c_proc_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 8a52e78b89f0..2b6394004ea1 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -233,6 +233,7 @@ #define I2C_HW_SMBUS_ALI1535 0x07 #define I2C_HW_SMBUS_SIS630 0x08 #define I2C_HW_SMBUS_SIS645 0x09 +#define I2C_HW_SMBUS_AMD8111 0x0a /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x00 diff --git a/include/linux/i2c-proc.h b/include/linux/i2c-proc.h index 4a4c33db48d5..ccdd2a95b1d1 100644 --- a/include/linux/i2c-proc.h +++ b/include/linux/i2c-proc.h @@ -348,6 +348,31 @@ struct i2c_address_data { {NULL}}; \ SENSORS_INSMOD +#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \ + enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \ + SENSORS_MODULE_PARM(force, \ + "List of adapter,address pairs to boldly assume " \ + "to be present"); \ + SENSORS_MODULE_PARM_FORCE(chip1); \ + SENSORS_MODULE_PARM_FORCE(chip2); \ + SENSORS_MODULE_PARM_FORCE(chip3); \ + SENSORS_MODULE_PARM_FORCE(chip4); \ + SENSORS_MODULE_PARM_FORCE(chip5); \ + SENSORS_MODULE_PARM_FORCE(chip6); \ + SENSORS_MODULE_PARM_FORCE(chip7); \ + SENSORS_MODULE_PARM_FORCE(chip8); \ + static struct i2c_force_data forces[] = {{force,any_chip}, \ + {force_ ## chip1,chip1}, \ + {force_ ## chip2,chip2}, \ + {force_ ## chip3,chip3}, \ + {force_ ## chip4,chip4}, \ + {force_ ## chip5,chip5}, \ + {force_ ## chip6,chip6}, \ + {force_ ## chip7,chip7}, \ + {force_ ## chip8,chip8}, \ + {NULL}}; \ + SENSORS_INSMOD + typedef int i2c_found_addr_proc(struct i2c_adapter *adapter, int addr, unsigned short flags, int kind); diff --git a/include/linux/sensors.h b/include/linux/sensors.h new file mode 100644 index 000000000000..31998faab1e6 --- /dev/null +++ b/include/linux/sensors.h @@ -0,0 +1,690 @@ +/* + sensors.h - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef SENSORS_NSENSORS_H +#define SENSORS_NSENSORS_H + +#define LM_DATE "20020915" +#define LM_VERSION "2.6.5" + +#include + +#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM78_SYSCTL_IN1 1001 +#define LM78_SYSCTL_IN2 1002 +#define LM78_SYSCTL_IN3 1003 +#define LM78_SYSCTL_IN4 1004 +#define LM78_SYSCTL_IN5 1005 +#define LM78_SYSCTL_IN6 1006 +#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM78_SYSCTL_FAN2 1102 +#define LM78_SYSCTL_FAN3 1103 +#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ +#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM78_ALARM_IN0 0x0001 +#define LM78_ALARM_IN1 0x0002 +#define LM78_ALARM_IN2 0x0004 +#define LM78_ALARM_IN3 0x0008 +#define LM78_ALARM_IN4 0x0100 +#define LM78_ALARM_IN5 0x0200 +#define LM78_ALARM_IN6 0x0400 +#define LM78_ALARM_FAN1 0x0040 +#define LM78_ALARM_FAN2 0x0080 +#define LM78_ALARM_FAN3 0x0800 +#define LM78_ALARM_TEMP 0x0010 +#define LM78_ALARM_BTI 0x0020 +#define LM78_ALARM_CHAS 0x1000 +#define LM78_ALARM_FIFO 0x2000 +#define LM78_ALARM_SMI_IN 0x4000 + +#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ +#define W83781D_SYSCTL_IN1 1001 +#define W83781D_SYSCTL_IN2 1002 +#define W83781D_SYSCTL_IN3 1003 +#define W83781D_SYSCTL_IN4 1004 +#define W83781D_SYSCTL_IN5 1005 +#define W83781D_SYSCTL_IN6 1006 +#define W83781D_SYSCTL_IN7 1007 +#define W83781D_SYSCTL_IN8 1008 +#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ +#define W83781D_SYSCTL_FAN2 1102 +#define W83781D_SYSCTL_FAN3 1103 +#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ +#define W83781D_SYSCTL_VRM 1301 +#define W83781D_SYSCTL_PWM1 1401 +#define W83781D_SYSCTL_PWM2 1402 +#define W83781D_SYSCTL_PWM3 1403 +#define W83781D_SYSCTL_PWM4 1404 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ +#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ +#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ +#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ +#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ + +#define W83781D_ALARM_IN0 0x0001 +#define W83781D_ALARM_IN1 0x0002 +#define W83781D_ALARM_IN2 0x0004 +#define W83781D_ALARM_IN3 0x0008 +#define W83781D_ALARM_IN4 0x0100 +#define W83781D_ALARM_IN5 0x0200 +#define W83781D_ALARM_IN6 0x0400 +#define W83782D_ALARM_IN7 0x10000 +#define W83782D_ALARM_IN8 0x20000 +#define W83781D_ALARM_FAN1 0x0040 +#define W83781D_ALARM_FAN2 0x0080 +#define W83781D_ALARM_FAN3 0x0800 +#define W83781D_ALARM_TEMP1 0x0010 +#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ +#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ +#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ +#define W83781D_ALARM_CHAS 0x1000 + +#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ + +#define ADM1021_SYSCTL_TEMP 1200 +#define ADM1021_SYSCTL_REMOTE_TEMP 1201 +#define ADM1021_SYSCTL_DIE_CODE 1202 +#define ADM1021_SYSCTL_ALARMS 1203 + +#define ADM1021_ALARM_TEMP_HIGH 0x40 +#define ADM1021_ALARM_TEMP_LOW 0x20 +#define ADM1021_ALARM_RTEMP_HIGH 0x10 +#define ADM1021_ALARM_RTEMP_LOW 0x08 +#define ADM1021_ALARM_RTEMP_NA 0x04 + +#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL518_SYSCTL_VIN1 1001 +#define GL518_SYSCTL_VIN2 1002 +#define GL518_SYSCTL_VIN3 1003 +#define GL518_SYSCTL_FAN1 1101 /* RPM */ +#define GL518_SYSCTL_FAN2 1102 +#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL518_SYSCTL_BEEP 2002 /* bitvector */ +#define GL518_SYSCTL_FAN1OFF 2003 +#define GL518_SYSCTL_ITERATE 2004 + +#define GL518_ALARM_VDD 0x01 +#define GL518_ALARM_VIN1 0x02 +#define GL518_ALARM_VIN2 0x04 +#define GL518_ALARM_VIN3 0x08 +#define GL518_ALARM_TEMP 0x10 +#define GL518_ALARM_FAN1 0x20 +#define GL518_ALARM_FAN2 0x40 + +#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL520_SYSCTL_VIN1 1001 +#define GL520_SYSCTL_VIN2 1002 +#define GL520_SYSCTL_VIN3 1003 +#define GL520_SYSCTL_VIN4 1004 +#define GL520_SYSCTL_FAN1 1101 /* RPM */ +#define GL520_SYSCTL_FAN2 1102 +#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define GL520_SYSCTL_VID 1300 +#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL520_SYSCTL_BEEP 2002 /* bitvector */ +#define GL520_SYSCTL_FAN1OFF 2003 +#define GL520_SYSCTL_CONFIG 2004 + +#define GL520_ALARM_VDD 0x01 +#define GL520_ALARM_VIN1 0x02 +#define GL520_ALARM_VIN2 0x04 +#define GL520_ALARM_VIN3 0x08 +#define GL520_ALARM_TEMP1 0x10 +#define GL520_ALARM_FAN1 0x20 +#define GL520_ALARM_FAN2 0x40 +#define GL520_ALARM_TEMP2 0x80 +#define GL520_ALARM_VIN4 0x80 + +#define EEPROM_SYSCTL1 1000 +#define EEPROM_SYSCTL2 1001 +#define EEPROM_SYSCTL3 1002 +#define EEPROM_SYSCTL4 1003 +#define EEPROM_SYSCTL5 1004 +#define EEPROM_SYSCTL6 1005 +#define EEPROM_SYSCTL7 1006 +#define EEPROM_SYSCTL8 1007 +#define EEPROM_SYSCTL9 1008 +#define EEPROM_SYSCTL10 1009 +#define EEPROM_SYSCTL11 1010 +#define EEPROM_SYSCTL12 1011 +#define EEPROM_SYSCTL13 1012 +#define EEPROM_SYSCTL14 1013 +#define EEPROM_SYSCTL15 1014 +#define EEPROM_SYSCTL16 1015 + +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM9240_SYSCTL_IN1 1001 +#define ADM9240_SYSCTL_IN2 1002 +#define ADM9240_SYSCTL_IN3 1003 +#define ADM9240_SYSCTL_IN4 1004 +#define ADM9240_SYSCTL_IN5 1005 +#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM9240_SYSCTL_FAN2 1102 +#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM9240_SYSCTL_ANALOG_OUT 2002 +#define ADM9240_SYSCTL_VID 2003 + +#define ADM9240_ALARM_IN0 0x0001 +#define ADM9240_ALARM_IN1 0x0002 +#define ADM9240_ALARM_IN2 0x0004 +#define ADM9240_ALARM_IN3 0x0008 +#define ADM9240_ALARM_IN4 0x0100 +#define ADM9240_ALARM_IN5 0x0200 +#define ADM9240_ALARM_FAN1 0x0040 +#define ADM9240_ALARM_FAN2 0x0080 +#define ADM9240_ALARM_TEMP 0x0010 +#define ADM9240_ALARM_CHAS 0x1000 + +#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1024_SYSCTL_IN1 1001 +#define ADM1024_SYSCTL_IN2 1002 +#define ADM1024_SYSCTL_IN3 1003 +#define ADM1024_SYSCTL_IN4 1004 +#define ADM1024_SYSCTL_IN5 1005 +#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM1024_SYSCTL_FAN2 1102 +#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */ +#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */ +#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1024_SYSCTL_ANALOG_OUT 2002 +#define ADM1024_SYSCTL_VID 2003 + +#define ADM1024_ALARM_IN0 0x0001 +#define ADM1024_ALARM_IN1 0x0002 +#define ADM1024_ALARM_IN2 0x0004 +#define ADM1024_ALARM_IN3 0x0008 +#define ADM1024_ALARM_IN4 0x0100 +#define ADM1024_ALARM_IN5 0x0200 +#define ADM1024_ALARM_FAN1 0x0040 +#define ADM1024_ALARM_FAN2 0x0080 +#define ADM1024_ALARM_TEMP 0x0010 +#define ADM1024_ALARM_TEMP1 0x0020 +#define ADM1024_ALARM_TEMP2 0x0001 +#define ADM1024_ALARM_CHAS 0x1000 + +#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1025_SYSCTL_IN1 1001 +#define ADM1025_SYSCTL_IN2 1002 +#define ADM1025_SYSCTL_IN3 1003 +#define ADM1025_SYSCTL_IN4 1004 +#define ADM1025_SYSCTL_IN5 1005 +#define ADM1025_SYSCTL_RTEMP 1251 +#define ADM1025_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1025_SYSCTL_ANALOG_OUT 2002 +#define ADM1025_SYSCTL_VID 2003 +#define ADM1025_SYSCTL_VRM 2004 + +#define ADM1025_ALARM_IN0 0x0001 +#define ADM1025_ALARM_IN1 0x0002 +#define ADM1025_ALARM_IN2 0x0004 +#define ADM1025_ALARM_IN3 0x0008 +#define ADM1025_ALARM_IN4 0x0100 +#define ADM1025_ALARM_IN5 0x0200 +#define ADM1025_ALARM_RTEMP 0x0020 +#define ADM1025_ALARM_TEMP 0x0010 + +#define LTC1710_SYSCTL_SWITCH_1 1000 +#define LTC1710_SYSCTL_SWITCH_2 1001 + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 + +#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ +#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ +#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ +#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */ +#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celcius */ +#define MAXI_SYSCTL_PLL 1301 /* MHz */ +#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ +#define MAXI_SYSCTL_VID2 1402 /* Volts */ +#define MAXI_SYSCTL_VID3 1403 /* Volts */ +#define MAXI_SYSCTL_VID4 1404 /* Volts */ +#define MAXI_SYSCTL_VID5 1405 /* Volts */ +#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ +#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ +#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ +#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ +#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ + +#define MAXI_ALARM_VID4 0x0001 +#define MAXI_ALARM_TEMP2 0x0002 +#define MAXI_ALARM_VID1 0x0004 +#define MAXI_ALARM_VID2 0x0008 +#define MAXI_ALARM_VID3 0x0010 +#define MAXI_ALARM_PLL 0x0080 +#define MAXI_ALARM_TEMP4 0x0100 +#define MAXI_ALARM_TEMP5 0x0200 +#define MAXI_ALARM_FAN1 0x1000 +#define MAXI_ALARM_FAN2 0x2000 +#define MAXI_ALARM_FAN3 0x4000 + +#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ +#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ +#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ +#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ + +#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ +#define SIS5595_SYSCTL_IN1 1001 +#define SIS5595_SYSCTL_IN2 1002 +#define SIS5595_SYSCTL_IN3 1003 +#define SIS5595_SYSCTL_IN4 1004 +#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SIS5595_SYSCTL_FAN2 1102 +#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ + +#define SIS5595_ALARM_IN0 0x01 +#define SIS5595_ALARM_IN1 0x02 +#define SIS5595_ALARM_IN2 0x04 +#define SIS5595_ALARM_IN3 0x08 +#define SIS5595_ALARM_BTI 0x20 +#define SIS5595_ALARM_FAN1 0x40 +#define SIS5595_ALARM_FAN2 0x80 +#define SIS5595_ALARM_IN4 0x8000 +#define SIS5595_ALARM_TEMP 0x8000 + +#define VIA686A_SYSCTL_IN0 1000 +#define VIA686A_SYSCTL_IN1 1001 +#define VIA686A_SYSCTL_IN2 1002 +#define VIA686A_SYSCTL_IN3 1003 +#define VIA686A_SYSCTL_IN4 1004 +#define VIA686A_SYSCTL_FAN1 1101 +#define VIA686A_SYSCTL_FAN2 1102 +#define VIA686A_SYSCTL_TEMP 1200 +#define VIA686A_SYSCTL_TEMP2 1201 +#define VIA686A_SYSCTL_TEMP3 1202 +#define VIA686A_SYSCTL_FAN_DIV 2000 +#define VIA686A_SYSCTL_ALARMS 2001 + +#define VIA686A_ALARM_IN0 0x01 +#define VIA686A_ALARM_IN1 0x02 +#define VIA686A_ALARM_IN2 0x04 +#define VIA686A_ALARM_IN3 0x08 +#define VIA686A_ALARM_TEMP 0x10 +#define VIA686A_ALARM_FAN1 0x40 +#define VIA686A_ALARM_FAN2 0x80 +#define VIA686A_ALARM_IN4 0x100 +#define VIA686A_ALARM_TEMP2 0x800 +#define VIA686A_ALARM_CHAS 0x1000 +#define VIA686A_ALARM_TEMP3 0x8000 + +#define ICSPLL_SYSCTL1 1000 + +#define BT869_SYSCTL_STATUS 1000 +#define BT869_SYSCTL_NTSC 1001 +#define BT869_SYSCTL_HALF 1002 +#define BT869_SYSCTL_RES 1003 +#define BT869_SYSCTL_COLORBARS 1004 +#define BT869_SYSCTL_DEPTH 1005 +#define BT869_SYSCTL_SVIDEO 1006 + +#define MATORB_SYSCTL_DISP 1000 + +#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celcius */ +#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celcius */ +#define THMC50_SYSCTL_INTER 1202 +#define THMC50_SYSCTL_INTER_MASK 1203 +#define THMC50_SYSCTL_DIE_CODE 1204 +#define THMC50_SYSCTL_ANALOG_OUT 1205 + +#define DDCMON_SYSCTL_ID 1010 +#define DDCMON_SYSCTL_SIZE 1011 +#define DDCMON_SYSCTL_SYNC 1012 +#define DDCMON_SYSCTL_TIMINGS 1013 +#define DDCMON_SYSCTL_SERIAL 1014 + +#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM87_SYSCTL_IN1 1001 +#define LM87_SYSCTL_IN2 1002 +#define LM87_SYSCTL_IN3 1003 +#define LM87_SYSCTL_IN4 1004 +#define LM87_SYSCTL_IN5 1005 +#define LM87_SYSCTL_AIN1 1006 +#define LM87_SYSCTL_AIN2 1007 +#define LM87_SYSCTL_FAN1 1102 +#define LM87_SYSCTL_FAN2 1103 +#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ +#define LM87_SYSCTL_ANALOG_OUT 2002 +#define LM87_SYSCTL_VID 2003 +#define LM87_SYSCTL_VRM 2004 + +#define LM87_ALARM_IN0 0x0001 +#define LM87_ALARM_IN1 0x0002 +#define LM87_ALARM_IN2 0x0004 +#define LM87_ALARM_IN3 0x0008 +#define LM87_ALARM_TEMP1 0x0010 +#define LM87_ALARM_TEMP2 0x0020 +#define LM87_ALARM_TEMP3 0x0020 /* same?? */ +#define LM87_ALARM_FAN1 0x0040 +#define LM87_ALARM_FAN2 0x0080 +#define LM87_ALARM_IN4 0x0100 +#define LM87_ALARM_IN5 0x0200 +#define LM87_ALARM_RESERVED1 0x0400 +#define LM87_ALARM_RESERVED2 0x0800 +#define LM87_ALARM_CHAS 0x1000 +#define LM87_ALARM_THERM_SIG 0x2000 +#define LM87_ALARM_TEMP2_FAULT 0x4000 +#define LM87_ALARM_TEMP3_FAULT 0x08000 + +#define PCF8574_SYSCTL_READ 1000 +#define PCF8574_SYSCTL_WRITE 1001 + +#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ +#define MTP008_SYSCTL_IN1 1001 +#define MTP008_SYSCTL_IN2 1002 +#define MTP008_SYSCTL_IN3 1003 +#define MTP008_SYSCTL_IN4 1004 +#define MTP008_SYSCTL_IN5 1005 +#define MTP008_SYSCTL_IN6 1006 +#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MTP008_SYSCTL_FAN2 1102 +#define MTP008_SYSCTL_FAN3 1103 +#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ +#define MTP008_SYSCTL_PWM1 1401 +#define MTP008_SYSCTL_PWM2 1402 +#define MTP008_SYSCTL_PWM3 1403 +#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define MTP008_SYSCTL_SENS2 1502 +#define MTP008_SYSCTL_SENS3 1503 +#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ +#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ + +#define MTP008_ALARM_IN0 0x0001 +#define MTP008_ALARM_IN1 0x0002 +#define MTP008_ALARM_IN2 0x0004 +#define MTP008_ALARM_IN3 0x0008 +#define MTP008_ALARM_IN4 0x0100 +#define MTP008_ALARM_IN5 0x0200 +#define MTP008_ALARM_IN6 0x0400 +#define MTP008_ALARM_FAN1 0x0040 +#define MTP008_ALARM_FAN2 0x0080 +#define MTP008_ALARM_FAN3 0x0800 +#define MTP008_ALARM_TEMP1 0x0010 +#define MTP008_ALARM_TEMP2 0x0100 +#define MTP008_ALARM_TEMP3 0x0200 + +#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ +#define DS1621_ALARM_TEMP_HIGH 0x40 +#define DS1621_ALARM_TEMP_LOW 0x20 +#define DS1621_SYSCTL_ENABLE 2002 +#define DS1621_SYSCTL_CONTINUOUS 2003 +#define DS1621_SYSCTL_POLARITY 2004 + +#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define IT87_SYSCTL_IN1 1001 +#define IT87_SYSCTL_IN2 1002 +#define IT87_SYSCTL_IN3 1003 +#define IT87_SYSCTL_IN4 1004 +#define IT87_SYSCTL_IN5 1005 +#define IT87_SYSCTL_IN6 1006 +#define IT87_SYSCTL_IN7 1007 +#define IT87_SYSCTL_IN8 1008 +#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ +#define IT87_SYSCTL_FAN2 1102 +#define IT87_SYSCTL_FAN3 1103 +#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ +#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ +#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ + +#define IT87_ALARM_IN0 0x000100 +#define IT87_ALARM_IN1 0x000200 +#define IT87_ALARM_IN2 0x000400 +#define IT87_ALARM_IN3 0x000800 +#define IT87_ALARM_IN4 0x001000 +#define IT87_ALARM_IN5 0x002000 +#define IT87_ALARM_IN6 0x004000 +#define IT87_ALARM_IN7 0x008000 +#define IT87_ALARM_FAN1 0x0001 +#define IT87_ALARM_FAN2 0x0002 +#define IT87_ALARM_FAN3 0x0004 +#define IT87_ALARM_TEMP1 0x00010000 +#define IT87_ALARM_TEMP2 0x00020000 +#define IT87_ALARM_TEMP3 0x00040000 + +#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCPOS_SYSCTL_REV 2000 /* Revision */ +#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ +#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ + +#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ +#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ +#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ +#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ +#define FSCSCY_SYSCTL_REV 2000 /* Revision */ +#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ +#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ +#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ + +#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ +#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ +#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ +#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ +#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ +#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ +#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ + +#define ARP_SYSCTL1 1000 +#define ARP_SYSCTL2 1001 +#define ARP_SYSCTL3 1002 +#define ARP_SYSCTL4 1003 +#define ARP_SYSCTL5 1004 +#define ARP_SYSCTL6 1005 +#define ARP_SYSCTL7 1006 +#define ARP_SYSCTL8 1007 + +#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SMSC47M1_SYSCTL_FAN2 1102 +#define SMSC47M1_SYSCTL_PWM1 1401 +#define SMSC47M1_SYSCTL_PWM2 1402 +#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ + +#define SMSC47M1_ALARM_FAN1 0x0001 +#define SMSC47M1_ALARM_FAN2 0x0002 + +#define VT1211_SYSCTL_IN0 1000 +#define VT1211_SYSCTL_IN1 1001 +#define VT1211_SYSCTL_IN2 1002 +#define VT1211_SYSCTL_IN3 1003 +#define VT1211_SYSCTL_IN4 1004 +#define VT1211_SYSCTL_IN5 1005 +#define VT1211_SYSCTL_IN6 1006 +#define VT1211_SYSCTL_FAN1 1101 +#define VT1211_SYSCTL_FAN2 1102 +#define VT1211_SYSCTL_TEMP 1200 +#define VT1211_SYSCTL_TEMP2 1201 +#define VT1211_SYSCTL_TEMP3 1202 +#define VT1211_SYSCTL_TEMP4 1203 +#define VT1211_SYSCTL_TEMP5 1204 +#define VT1211_SYSCTL_TEMP6 1205 +#define VT1211_SYSCTL_TEMP7 1206 +#define VT1211_SYSCTL_VID 1300 +#define VT1211_SYSCTL_PWM1 1401 +#define VT1211_SYSCTL_PWM2 1402 +#define VT1211_SYSCTL_VRM 1600 +#define VT1211_SYSCTL_UCH 1700 +#define VT1211_SYSCTL_FAN_DIV 2000 +#define VT1211_SYSCTL_ALARMS 2001 + +#define VT1211_ALARM_IN1 0x01 +#define VT1211_ALARM_IN2 0x02 +#define VT1211_ALARM_IN5 0x04 +#define VT1211_ALARM_IN3 0x08 +#define VT1211_ALARM_TEMP 0x10 +#define VT1211_ALARM_FAN1 0x40 +#define VT1211_ALARM_FAN2 0x80 +#define VT1211_ALARM_IN4 0x100 +#define VT1211_ALARM_IN6 0x200 +#define VT1211_ALARM_TEMP2 0x800 +#define VT1211_ALARM_CHAS 0x1000 +#define VT1211_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP +#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 +#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 +#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 +#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 + +#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ +#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysterisis, input */ + +#define LM92_ALARM_TEMP_HIGH 0x01 +#define LM92_ALARM_TEMP_LOW 0x02 +#define LM92_ALARM_TEMP_CRIT 0x04 +#define LM92_TEMP_HIGH 0x08 +#define LM92_TEMP_LOW 0x10 +#define LM92_TEMP_CRIT 0x20 +#define LM92_TEMP_HYST 0x40 +#define LM92_TEMP_INPUT 0x80 + +#define VT8231_SYSCTL_IN0 1000 +#define VT8231_SYSCTL_IN1 1001 +#define VT8231_SYSCTL_IN2 1002 +#define VT8231_SYSCTL_IN3 1003 +#define VT8231_SYSCTL_IN4 1004 +#define VT8231_SYSCTL_IN5 1005 +#define VT8231_SYSCTL_IN6 1006 +#define VT8231_SYSCTL_FAN1 1101 +#define VT8231_SYSCTL_FAN2 1102 +#define VT8231_SYSCTL_TEMP 1200 +#define VT8231_SYSCTL_TEMP2 1201 +#define VT8231_SYSCTL_TEMP3 1202 +#define VT8231_SYSCTL_TEMP4 1203 +#define VT8231_SYSCTL_TEMP5 1204 +#define VT8231_SYSCTL_TEMP6 1205 +#define VT8231_SYSCTL_TEMP7 1206 +#define VT8231_SYSCTL_VID 1300 +#define VT8231_SYSCTL_PWM1 1401 +#define VT8231_SYSCTL_PWM2 1402 +#define VT8231_SYSCTL_VRM 1600 +#define VT8231_SYSCTL_UCH 1700 +#define VT8231_SYSCTL_FAN_DIV 2000 +#define VT8231_SYSCTL_ALARMS 2001 + +#define VT8231_ALARM_IN1 0x01 +#define VT8231_ALARM_IN2 0x02 +#define VT8231_ALARM_IN5 0x04 +#define VT8231_ALARM_IN3 0x08 +#define VT8231_ALARM_TEMP 0x10 +#define VT8231_ALARM_FAN1 0x40 +#define VT8231_ALARM_FAN2 0x80 +#define VT8231_ALARM_IN4 0x100 +#define VT8231_ALARM_IN6 0x200 +#define VT8231_ALARM_TEMP2 0x800 +#define VT8231_ALARM_CHAS 0x1000 +#define VT8231_ALARM_TEMP3 0x8000 +/* duplicates */ +#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP +#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN1 +#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN2 +#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN3 +#define VT8231_ALARM_TEMP7 VT8231_ALARM_IN4 + +#define SMARTBATT_SYSCTL_I 1001 +#define SMARTBATT_SYSCTL_V 1002 +#define SMARTBATT_SYSCTL_TEMP 1003 +#define SMARTBATT_SYSCTL_TIME 1004 +#define SMARTBATT_SYSCTL_ALARMS 1005 +#define SMARTBATT_SYSCTL_CHARGE 1006 + + +#endif /* def SENSORS_SENSORS_H */ -- cgit v1.2.3 From a83c24f33622b86c3cb2a53f959a042d67ab7258 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 25 Dec 2002 23:27:03 -0800 Subject: [FB] Fix minor typos wrt readq/writeq support on 64-bit targets. --- drivers/video/cfbcopyarea.c | 2 +- include/linux/fb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') 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/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 -- cgit v1.2.3 From 1af3131d0c77394498c05b191267f9a7f8f8c225 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 25 Dec 2002 23:56:07 -0800 Subject: [FB] First cut at updating tgafb to 2.5 fb api. A large scale rewrite modeled off of skeletonfb.c. --- drivers/video/Makefile | 2 +- drivers/video/tgafb.c | 1499 ++++++++++++++++++++---------------------------- drivers/video/tgafb.h | 199 ------- include/video/tgafb.h | 210 +++++++ 4 files changed, 825 insertions(+), 1085 deletions(-) delete mode 100644 drivers/video/tgafb.h create mode 100644 include/video/tgafb.h (limited to 'include') diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d9767337fe1f..96bf3caaebab 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 diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 325f0ab1ae6c..2db3eced1d38 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -2,10 +2,10 @@ * 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 + * 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 @@ -28,982 +28,711 @@ * KNOWN PROBLEMS/TO DO ==================================================== */ #include -#include #include +#include #include #include #include #include #include -#include #include -#include -#include #include -#include +#include #include -#include +#include #include - -#include