]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14d 0.99.14d
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:16 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:16 +0000 (15:09 -0500)
18 files changed:
Makefile
drivers/char/console.c
drivers/scsi/aha152x.c
fs/isofs/dir.c
fs/isofs/inode.c
fs/isofs/namei.c
fs/proc/array.c
fs/proc/root.c
include/linux/fs.h
include/linux/module.h [new file with mode: 0644]
include/linux/sys.h
include/linux/unistd.h
kernel/Makefile
kernel/ksyms.S [new file with mode: 0644]
kernel/ksyms.sh [new file with mode: 0644]
kernel/module.c [new file with mode: 0644]
kernel/sched.c
mm/vmalloc.c

index 626f0f231fa488b8bae251a3c0708684be696862..32909df34c82db1db2136d616d597ebb332ac174 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
 PATCHLEVEL = 14
-ALPHA = c
+ALPHA = d
 
 all:   Version zImage
 
index 3e2b0da22c15a1a419020c32ade47b5d5d9f5d12..c6c3cf76cc7bb95c3de43f49bbf4bf5772abc8dd 100644 (file)
@@ -974,6 +974,7 @@ void con_write(struct tty_struct * tty)
        if (!EMPTY(&tty->write_q) && currcons == sel_cons)
                clear_selection();
 #endif /* CONFIG_SELECTION */
+       disable_bh(KEYBOARD_BH);
        while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) {
                if (state == ESnormal && translate[c]) {
                        if (need_wrap) {
@@ -1270,9 +1271,9 @@ void con_write(struct tty_struct * tty)
                                state = ESnormal;
                }
        }
-       if (vcmode == KD_GRAPHICS)
-               return;
-       set_cursor(currcons);
+       if (vcmode != KD_GRAPHICS)
+               set_cursor(currcons);
+       enable_bh(KEYBOARD_BH);
 }
 
 void do_keyboard_interrupt(void)
@@ -1288,7 +1289,7 @@ void do_keyboard_interrupt(void)
                timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
                timer_active |= 1<<BLANK_TIMER;
        }
-}      
+}
 
 void * memsetw(void * s,unsigned short c,int count)
 {
index 1f90af8a6d417a2ee7f5ebdac4a8a65a7606295e..17010fb9b26f2f82e25df011e57dfa66ef1aa0a8 100644 (file)
  * General Public License for more details.
  
  *
- * $Id: aha152x.c,v 0.99 1993/10/24 16:19:59 root Exp root $
+ * $Id: aha152x.c,v 0.101 1993/12/13 01:16:27 root Exp $
  *
 
  * $Log: aha152x.c,v $
+ * Revision 0.101  1993/12/13  01:16:27  root
+ * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
+ *   fixes problems with CD-ROM sector size detection & media change)
+ *
+ * Revision 0.100  1993/12/10  16:58:47  root
+ * - fix for unsuccessful selections in case of non-continuous id assignments
+ *   on the scsi bus.
+ *
  * Revision 0.99  1993/10/24  16:19:59  root
  * - fixed DATA IN (rare read errors gone)
  *
 #define P_BUSFREE  1
 #define P_PARITY   2
 
-char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.99 $\n";
+char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.101 $\n";
 
 static int port_base      = 0;
 static int this_host      = 0;
@@ -662,6 +670,7 @@ int aha152x_detect(int hostno)
   SETBITS(SCSISEQ, SCSIRSTO );
   do_pause(5);
   CLRBITS(SCSISEQ, SCSIRSTO );
+  do_pause(10);
 
   aha152x_reset(NULL);
 
@@ -948,6 +957,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
        SETPORT(SCSISEQ, SCSIRSTO);
        do_pause(5);
        SETPORT(SCSISEQ, 0);
+       do_pause(10);
 
        SETPORT(SIMODE0, 0 );
        SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
@@ -1140,7 +1150,7 @@ void aha152x_intr( int irqno )
 
       SETPORT( SXFRCTL0, CH1);
 
-      identify_msg = GETPORT(SCSIDAT);
+      identify_msg = GETPORT(SCSIBUS);
 
       if(!(identify_msg & IDENTIFY_BASE))
         {
@@ -1301,6 +1311,9 @@ void aha152x_intr( int irqno )
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
           printk("SELTO, ");
 #endif
+         /* end selection attempt */
+          CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+
           /* timeout */
           SETPORT( SSTAT1, CLRSELTIMO );
 
@@ -1498,7 +1511,7 @@ void aha152x_intr( int irqno )
   
       while( phase == P_MSGI ) 
         {
-          current_SC->SCp.Message = GETPORT( SCSIDAT );
+          current_SC->SCp.Message = GETPORT( SCSIBUS );
           switch(current_SC->SCp.Message)
             {
             case DISCONNECT:
@@ -1541,7 +1554,7 @@ void aha152x_intr( int irqno )
                 if(getphase()!=P_MSGI)
                   break;
   
-                i=GETPORT(SCSIDAT);
+                i=GETPORT(SCSIBUS);
 
 #if defined(DEBUG_MSGI)
                 printk("length (%d), ", i);
@@ -1555,7 +1568,7 @@ void aha152x_intr( int irqno )
                 if(getphase()!=P_MSGI)
                   break;
 
-                code = GETPORT(SCSIDAT);
+                code = GETPORT(SCSIBUS);
 
                 switch( code )
                   {
@@ -1598,9 +1611,9 @@ void aha152x_intr( int irqno )
                 while( --i && (make_acklow(), getphase()==P_MSGI))
                   {
 #if defined(DEBUG_MSGI)
-                    printk("%x ", GETPORT(SCSIDAT) );
+                    printk("%x ", GETPORT(SCSIBUS) );
 #else
-                    GETPORT(SCSIDAT);
+                    GETPORT(SCSIBUS);
 #endif
                   }
 #if defined(DEBUG_MSGI)
@@ -1655,24 +1668,12 @@ void aha152x_intr( int irqno )
       SETPORT( SXFRCTL0, CH1);
 
       SETPORT( SIMODE0, 0 );
-      SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT );
-
-      SETBITS( SXFRCTL0, SCSIEN );
-#if defined(DEBUG_STATUS)
-      printk("waiting for status, ");
-#endif
-#if defined(DEBUG_STATUS)
-      disp_ports();
-#endif
-      while( TESTLO( DMASTAT, INTSTAT ) )
-        ;
-
-#if 0
-      if(TESTLO( SSTAT0, SPIORDY ) )
-        aha152x_panic("passing STATUS phase");
-#endif
+      SETPORT( SIMODE1, ENREQINIT );
 
-      current_SC->SCp.Status = GETPORT( SCSIDAT );
+      if( TESTHI( SSTAT1, PHASEMIS ) )
+       printk("aha152x: passing STATUS phase");
+       
+      current_SC->SCp.Status = GETPORT( SCSIBUS );
       make_acklow();
       getphase();
 
@@ -1680,13 +1681,6 @@ void aha152x_intr( int irqno )
       printk("inbound status ");
       print_status( current_SC->SCp.Status );
       printk(", ");
-#endif
-      CLRBITS( SXFRCTL0, SCSIEN );
-      while( TESTHI( SXFRCTL0, SCSIEN ) )
-        ;
-        
-#if 0
-      CLRBITS( SXFRCTL0, SPIOEN);
 #endif
       break;
 
index 6a78e08b3a37e75dafde988f752d54d819b7f2cb..ed5884ab502aec262c4314c33423b86f9dda41f3 100644 (file)
@@ -126,8 +126,10 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
                        offset = filp->f_pos & (bufsize - 1);
                        block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
                        if (!block
-                           || !(bh = bread(inode->i_dev,block,bufsize)))
+                           || !(bh = bread(inode->i_dev,block,bufsize))) {
+                               kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
                                return 0;
+                       };
                        memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
                }
                
index dc17d795510df085dfa20f82227b9ae2b88a3d8d..01eb341215e75e60d4a921ce3530f8fa197af8d9 100644 (file)
@@ -585,6 +585,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent)
 
                if (offset >= bufsize)
                {
+                       if((block & 1) != 0) return -1;
                        cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
                        memcpy(cpnt, bh->b_data, bufsize);
                        de = (struct iso_directory_record *)
@@ -592,9 +593,10 @@ int isofs_lookup_grandparent(struct inode * parent, int extent)
                        brelse(bh);
                        offset -= bufsize;
                        block++;
-                       if((block & 1) == 0) return -1;
-                       if (!(bh = bread(parent->i_dev,block,bufsize)))
+                       if (!(bh = bread(parent->i_dev,block,bufsize))) {
+                               kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
                                return -1;
+                       };
                        memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
                }
                
index fc7cc24455ee9e40e3a386eb121ddba50cd93d84..a2713779bd096dcd421d9a6604ed89127d08c714 100644 (file)
@@ -122,8 +122,10 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
                        brelse(bh);
                        offset = f_pos & (bufsize - 1);
                        block = isofs_bmap(dir,f_pos>>bufbits);
-                       if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
+                       if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
+                               kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
                                return 0;
+                       };
                        memcpy((char *)cpnt+bufsize,bh->b_data,bufsize);
                }
                
index 28690e6ce23fb759b2fb1ed3b018b2b448745936..f25bc5614333738bec4989217c41c19ec2462ac1 100644 (file)
@@ -413,6 +413,8 @@ static int get_maps(int pid, char *buf)
        return sz;
 }
 
+asmlinkage int get_module_list( char *);
+
 static int array_read(struct inode * inode, struct file * file,char * buf, int count)
 {
        char * page;
@@ -463,6 +465,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
                case 15:
                        length = get_maps(pid, page);
                        break;
+               case 16:
+                       length = get_module_list(page);
+                       break;
                default:
                        free_page((unsigned long) page);
                        return -EBADF;
index 0890d25bb94927cff973ae6be950e17ac8450e71..9d9127de2be4a147d30ae147f367ed2a1d1d696f 100644 (file)
@@ -65,6 +65,7 @@ static struct proc_dir_entry root_dir[] = {
        {13,6,"malloc" },
 #endif
        {14,5,"kcore" },
+       {16,7,"modules" },
 };
 
 #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
index b8e4c6266e2512c3a7bbbb142702add69933bb07..ff67235e7f8a0ed0de58a8e1f2a3400d3b523b63 100644 (file)
@@ -319,6 +319,7 @@ extern struct file_operations def_blk_fops;
 extern struct inode_operations blkdev_inode_operations;
 
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_chrdev( unsigned int major, const char * name);
 extern int chrdev_open(struct inode * inode, struct file * filp);
 extern struct file_operations def_chr_fops;
 extern struct inode_operations chrdev_inode_operations;
diff --git a/include/linux/module.h b/include/linux/module.h
new file mode 100644 (file)
index 0000000..117478c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Dynamic loading of modules into the kernel.
+ */
+
+#ifndef _LINUX_MODULE_H
+#define _LINUX_MODULE_H
+
+/* values of module.state */
+#define MOD_UNINITIALIZED 0
+#define MOD_RUNNING 1
+#define MOD_DELETED 2
+
+/* maximum length of module name */
+#define MOD_MAX_NAME 64
+
+/* maximum length of symbol name */
+#define SYM_MAX_NAME 60
+
+
+struct module {
+       struct module *next;
+       char *name;
+       int size;                       /* size of module in pages */
+       void* addr;                     /* address of module */
+       int state;
+       void (*cleanup)(void);          /* cleanup routine */
+};
+
+
+struct mod_routines {
+       int (*init)(void);              /* initialization routine */
+       void (*cleanup)(void);          /* cleanup routine */
+};
+
+
+struct kernel_sym {
+       unsigned long value;            /* value of symbol */
+       char name[SYM_MAX_NAME];        /* name of symbol */
+};
+
+extern struct module *module_list;
+
+
+/*
+ * The first word of the module contains the use count.
+ */
+#define GET_USE_COUNT(module)  (* (int *) (module)->addr)
+/*
+ * define the count variable, and usage macros.
+ */
+
+extern int mod_use_count_;
+
+#define MOD_INC_USE_COUNT      mod_use_count_++
+#define MOD_DEC_USE_COUNT      mod_use_count_--
+#define MOD_IN_USE            (mod_use_count_ != 0)
+
+#endif
index da8ce5b617a77710d63dd996dbd5b4376f8defb3..401f11c2e4e8fecf7ead30a9a4a419c4d9fa6064 100644 (file)
 extern "C" {
 #endif
 
-extern int sys_setup();
+extern int sys_setup();         /* 0 */
 extern int sys_exit();
 extern int sys_fork();
 extern int sys_read();
 extern int sys_write();
-extern int sys_open();
+extern int sys_open();          /* 5 */
 extern int sys_close();
 extern int sys_waitpid();
 extern int sys_creat();
 extern int sys_link();
-extern int sys_unlink();
+extern int sys_unlink();        /* 10 */
 extern int sys_execve();
 extern int sys_chdir();
 extern int sys_time();
 extern int sys_mknod();
-extern int sys_chmod();
+extern int sys_chmod();         /* 15 */
 extern int sys_chown();
 extern int sys_break();
 extern int sys_stat();
 extern int sys_lseek();
-extern int sys_getpid();
+extern int sys_getpid();        /* 20 */
 extern int sys_mount();
 extern int sys_umount();
 extern int sys_setuid();
 extern int sys_getuid();
-extern int sys_stime();
+extern int sys_stime();         /* 25 */
 extern int sys_ptrace();
 extern int sys_alarm();
 extern int sys_fstat();
 extern int sys_pause();
-extern int sys_utime();
+extern int sys_utime();         /* 30 */
 extern int sys_stty();
 extern int sys_gtty();
 extern int sys_access();
 extern int sys_nice();
-extern int sys_ftime();
+extern int sys_ftime();         /* 35 */
 extern int sys_sync();
 extern int sys_kill();
 extern int sys_rename();
 extern int sys_mkdir();
-extern int sys_rmdir();
+extern int sys_rmdir();         /* 40 */
 extern int sys_dup();
 extern int sys_pipe();
 extern int sys_times();
 extern int sys_prof();
-extern int sys_brk();
+extern int sys_brk();           /* 45 */
 extern int sys_setgid();
 extern int sys_getgid();
 extern int sys_signal();
 extern int sys_geteuid();
-extern int sys_getegid();
+extern int sys_getegid();       /* 50 */
 extern int sys_acct();
 extern int sys_phys();
 extern int sys_lock();
 extern int sys_ioctl();
-extern int sys_fcntl();
+extern int sys_fcntl();         /* 55 */
 extern int sys_mpx();
 extern int sys_setpgid();
 extern int sys_ulimit();
 extern int sys_uname();
-extern int sys_umask();
+extern int sys_umask();         /* 60 */
 extern int sys_chroot();
 extern int sys_ustat();
 extern int sys_dup2();
 extern int sys_getppid();
-extern int sys_getpgrp();
+extern int sys_getpgrp();       /* 65 */
 extern int sys_setsid();
 extern int sys_sigaction();
 extern int sys_sgetmask();
 extern int sys_ssetmask();
-extern int sys_setreuid();
+extern int sys_setreuid();      /* 70 */
 extern int sys_setregid();
 extern int sys_sigpending();
 extern int sys_sigsuspend();
 extern int sys_sethostname();
-extern int sys_setrlimit();
+extern int sys_setrlimit();     /* 75 */
 extern int sys_getrlimit();
 extern int sys_getrusage();
 extern int sys_gettimeofday();
 extern int sys_settimeofday();
-extern int sys_getgroups();
+extern int sys_getgroups();     /* 80 */
 extern int sys_setgroups();
 extern int sys_select();
 extern int sys_symlink();
 extern int sys_lstat();
-extern int sys_readlink();
+extern int sys_readlink();      /* 85 */
 extern int sys_uselib();
 extern int sys_swapon();
 extern int sys_reboot();
 extern int sys_readdir();
-extern int sys_mmap();
+extern int sys_mmap();          /* 90 */
 extern int sys_munmap();
 extern int sys_truncate();
 extern int sys_ftruncate();
 extern int sys_fchmod();
-extern int sys_fchown();
+extern int sys_fchown();        /* 95 */
 extern int sys_getpriority();
 extern int sys_setpriority();
 extern int sys_profil();
 extern int sys_statfs();
-extern int sys_fstatfs();
+extern int sys_fstatfs();       /* 100 */
 extern int sys_ioperm();
 extern int sys_socketcall();
 extern int sys_syslog();
 extern int sys_getitimer();
-extern int sys_setitimer();
+extern int sys_setitimer();     /* 105 */
 extern int sys_newstat();
 extern int sys_newlstat();
 extern int sys_newfstat();
 extern int sys_newuname();
-extern int sys_iopl();
+extern int sys_iopl();          /* 110 */
 extern int sys_vhangup();
 extern int sys_idle();
 extern int sys_vm86();
 extern int sys_wait4();
-extern int sys_swapoff();
+extern int sys_swapoff();       /* 115 */
 extern int sys_sysinfo();
 extern int sys_ipc();
 extern int sys_fsync();
 extern int sys_sigreturn();
-extern int sys_setdomainname();
+extern int sys_setdomainname(); /* 120 */
 extern int sys_olduname();
 extern int sys_old_syscall();
 extern int sys_modify_ldt();
 extern int sys_adjtimex();
-extern int sys_mprotect();
+extern int sys_mprotect();      /* 125 */
 extern int sys_sigprocmask();
+extern int sys_create_module();
+extern int sys_init_module();
+extern int sys_delete_module();
+extern int sys_get_kernel_syms(); /* 130 */
 
 /*
  * These are system calls that will be removed at some time
index 87aee7927a6703c46fd71a4c7aeaa68f76a10ca5..e06f3f251e9b00de912c7cd656fd67081b2264d0 100644 (file)
 #define __NR_adjtimex          124
 #define __NR_mprotect          125
 #define __NR_sigprocmask       126
+#define __NR_create_module     127
+#define __NR_init_module       128
+#define __NR_delete_module     129
+#define __NR_get_kernel_syms   130
 
 extern int errno;
 
index 0479a045d0315482ae31989236754bf1fd048f0c..49a191401597093e096c249bb414118e3d621c83 100644 (file)
@@ -17,7 +17,7 @@
        $(CC) $(CFLAGS) -c $<
 
 OBJS  = sched.o sys_call.o traps.o irq.o dma.o fork.o \
-       panic.o printk.o vsprintf.o sys.o exit.o \
+       panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
        signal.o mktime.o ptrace.o ioport.o itimer.o \
        info.o ldt.o time.o
 
@@ -34,6 +34,11 @@ sys_call.o: sys_call.s
 sched.o: sched.c
        $(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
 
+ksyms.o: ksyms.S ksyms.sh /usr/include/linux/autoconf.h
+       $(CPP) $(CFLAGS) ksyms.S > ksyms.lst
+       sh ksyms.sh > ksyms.s
+       $(AS) -o ksyms.o ksyms.s
 dep:
        $(CPP) -M *.c > .depend
 
diff --git a/kernel/ksyms.S b/kernel/ksyms.S
new file mode 100644 (file)
index 0000000..9532ee0
--- /dev/null
@@ -0,0 +1,28 @@
+#include <linux/autoconf.h>
+/* 
+ * Herein lies all the functions/variables that are "exported" for linkage
+ * With dynamically loaded kernel modules. Could do with making this a bit
+ * cleaner!
+ *
+ *  Jon.
+ */
+
+_register_chrdev
+_unregister_chrdev
+_verify_area
+_wake_up_interruptible
+
+_current
+_jiffies
+_printk
+_schedule
+
+#ifdef CONFIG_FTAPE
+#
+# The next labels are needed for ftape driver.
+#
+  _ftape_big_buffer
+  _xtime
+  _do_floppy
+  _tick
+#endif
diff --git a/kernel/ksyms.sh b/kernel/ksyms.sh
new file mode 100644 (file)
index 0000000..4a98ab1
--- /dev/null
@@ -0,0 +1,37 @@
+# This program will construct ksyms.s.  Ksyms.s contains a symbol table
+# for all the kernel symbols included in the file ksyms.lst.  The following
+# variables are defined in ksym.s:
+#
+#      int symbol_table_size;          /* number of symbols */
+#      struct {
+#              void *value;            /* value of symbol */
+#              char *name;             /* name of symbol */
+#      } symbol_table[];
+#
+#
+
+trap "rm -f ksyms.tmp ksyms.lst" 0 1 2 
+
+sed -e '/^#/d' -e '/^[  ]*$/d' ksyms.lst | sort > ksyms.tmp
+
+echo ' .data
+       .globl  _symbol_table_size, _symbol_table
+
+_symbol_table_size:'
+echo " .long" `wc -l < ksyms.tmp`
+echo '
+_symbol_table:'
+awk 'BEGIN {stringloc = 0}
+{print "       .long " $1; print "     .long strings+" stringloc; \
+        stringloc += length($1) + 1;}' ksyms.tmp
+echo '
+strings:'
+awk '{print "  .ascii \"" $1 "\\0\""}' ksyms.tmp
+
+
+
+#
+# Alternativly, if the kernel is c++ compiled:
+# By using gsub() we can forse all function names to appear as extern "C".
+# This allows linkable drivers written in C or C++ - Jon
+# awk '{gsub(/__F.*/, "") ; print "    .ascii \"" $0 "\\0\""}' ksyms.tmp
diff --git a/kernel/module.c b/kernel/module.c
new file mode 100644 (file)
index 0000000..9b0811a
--- /dev/null
@@ -0,0 +1,275 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <linux/mm.h>          /* defines GFP_KERNEL */
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+
+struct module *module_list = NULL;
+int freeing_modules;           /* true if some modules are marked for deletion */
+
+struct module *find_module( const char *name);
+int get_mod_name( char *user_name, char *buf);
+int free_modules( void);
+
+/*
+ * Allocate space for a module.
+ */
+asmlinkage int
+sys_create_module(char *module_name, unsigned long size)
+{
+       int npages;
+       void* addr;
+       int len;
+       char name[MOD_MAX_NAME];
+       char *savename;
+       struct module *mp;
+       int error;
+
+       if (!suser())
+               return -EPERM;
+       if (name == NULL || size == 0)
+               return -EINVAL;
+       if ((error = get_mod_name(module_name, name)) != 0)
+               return error;
+       if (find_module(name) != NULL) {
+               return -EEXIST;
+       }
+       len = strlen(name) + 1;
+       if ((savename = (char*) kmalloc(len, GFP_KERNEL)) == NULL)
+               return -ENOMEM;
+       memcpy(savename, name, len);
+       if ((mp = (struct module*) kmalloc(sizeof *mp, GFP_KERNEL)) == NULL) {
+               kfree(savename);
+               return -ENOMEM;
+       }
+       npages = (size + sizeof (int) + 4095) / 4096;
+       if ((addr = vmalloc(npages * 4096)) == 0) {
+               kfree_s(mp, sizeof *mp);
+               kfree(savename);
+               return -ENOMEM;
+       }
+       mp->name = savename;
+       mp->size = npages;
+       mp->addr = addr;
+       mp->state = MOD_UNINITIALIZED;
+       * (int *) addr = 0;             /* set use count to zero */
+       mp->cleanup = NULL;
+       mp->next = module_list;
+       module_list = mp;
+       printk("module `%s' (%lu pages @ 0x%08lx) created\n",
+               mp->name, (unsigned long) mp->size, (unsigned long) mp->addr);
+       return (int) addr;
+}
+
+/*
+ * Initialize a module.
+ */
+asmlinkage int
+sys_init_module(char *module_name, char *code, unsigned codesize,
+               struct mod_routines *routines)
+{
+       struct module *mp;
+       char name[MOD_MAX_NAME];
+       int error;
+       struct mod_routines rt;
+
+       if (!suser())
+               return -EPERM;
+       /*
+        * First reclaim any memory from dead modules that where not
+        * freed when deleted. Should I think be done by timers when
+        * the module was deleted - Jon.
+        */
+       free_modules();
+
+       if ((error = get_mod_name(module_name, name)) != 0)
+               return error;
+       printk( "initializing module `%s', %d (0x%x) bytes\n",
+               name, codesize, codesize);
+       memcpy_fromfs(&rt, routines, sizeof rt);
+       if ((mp = find_module(name)) == NULL)
+               return -ENOENT;
+       if ((codesize + sizeof (int) + 4095) / 4096 > mp->size)
+               return -EINVAL;
+       memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize);
+       memset((char *)mp->addr + sizeof (int) + codesize, 0,
+               mp->size * 4096 - (codesize + sizeof (int)));
+       printk( "  init enty @ 0x%08lx, cleanup entry @ 0x%08lx\n",
+               (unsigned long) rt.init, (unsigned long) rt.cleanup);
+       mp->cleanup = rt.cleanup;
+       if ((*rt.init)() != 0)
+               return -EBUSY;
+       mp->state = MOD_RUNNING;
+       return 0;
+}
+
+asmlinkage int
+sys_delete_module(char *module_name)
+{
+       struct module *mp;
+       char name[MOD_MAX_NAME];
+       int error;
+
+       if (!suser())
+               return -EPERM;
+       if (module_name != NULL) {
+               if ((error = get_mod_name(module_name, name)) != 0)
+                       return error;
+               if ((mp = find_module(name)) == NULL)
+                       return -ENOENT;
+               if (mp->state == MOD_RUNNING)
+                       (*mp->cleanup)();
+               mp->state = MOD_DELETED;
+       }
+       free_modules();
+       return 0;
+}
+
+/*
+ * Copy the kernel symbol table to user space.  If the argument is null,
+ * just return the size of the table.
+ */
+asmlinkage int
+sys_get_kernel_syms(struct kernel_sym *table)
+{
+       struct symbol {
+               unsigned long addr;
+               char *name;
+       };
+       extern int symbol_table_size;
+       extern struct symbol symbol_table[];
+       int i;
+       struct symbol *from;
+       struct kernel_sym *to;
+       struct kernel_sym sym;
+
+       if (table != NULL) {
+               from = symbol_table;
+               to = table;
+               verify_area(VERIFY_WRITE, to, symbol_table_size * sizeof *table);
+               for (i = symbol_table_size ; --i >= 0 ; ) {
+                       sym.value = from->addr;
+                       strncpy(sym.name, from->name, sizeof sym.name);
+                       memcpy_tofs(to, &sym, sizeof sym);
+                       from++, to++;
+               }
+       }
+       return symbol_table_size;
+}
+
+
+/*
+ * Copy the name of a module from user space.
+ */
+int
+get_mod_name(char *user_name, char *buf)
+{
+       int i;
+
+       i = 0;
+       for (i = 0 ; (buf[i] = get_fs_byte(user_name + i)) != '\0' ; ) {
+               if (++i >= MOD_MAX_NAME)
+                       return -E2BIG;
+       }
+       return 0;
+}
+
+
+/*
+ * Look for a module by name, ignoring modules marked for deletion.
+ */
+struct module *
+find_module( const char *name)
+{
+       struct module *mp;
+
+       for (mp = module_list ; mp ; mp = mp->next) {
+               if (mp->state == MOD_DELETED)
+                       continue;
+               if (!strcmp(mp->name, name))
+                       break;
+       }
+       return mp;
+}
+
+
+/*
+ * Try to free modules which have been marked for deletion.  Returns nonzero
+ * if a module was actually freed.
+ */
+int
+free_modules( void)
+{
+       struct module *mp;
+       struct module **mpp;
+       int did_deletion;
+
+       did_deletion = 0;
+       freeing_modules = 0;
+       mpp = &module_list;
+       while ((mp = *mpp) != NULL) {
+               if (mp->state != MOD_DELETED) {
+                       mpp = &mp->next;
+               } else if (GET_USE_COUNT(mp) != 0) {
+                       freeing_modules = 1;
+                       mpp = &mp->next;
+               } else {        /* delete it */
+                       *mpp = mp->next;
+                       vfree(mp->addr);
+                       kfree(mp->name);
+                       kfree_s(mp, sizeof *mp);
+                       did_deletion = 1;
+               }
+       }
+       return did_deletion;
+}
+
+
+/*
+ * Called by the /proc file system to return a current list of modules.
+ */
+int
+get_module_list( char *buf)
+{
+       char *p;
+       char *q;
+       int i;
+       struct module *mp;
+       char size[32];
+
+       p = buf;
+       for (mp = module_list ; mp ; mp = mp->next) {
+               if (p - buf > 4096 - 100)
+                       break;                  /* avoid overflowing buffer */
+               q = mp->name;
+               i = 20;
+               while (*q) {
+                       *p++ = *q++;
+                       i--;
+               }
+               sprintf(size, "%d", mp->size);
+               i -= strlen(size);
+               if (i <= 0)
+                       i = 1;
+               while (--i >= 0)
+                       *p++ = ' ';
+               q = size;
+               while (*q)
+                       *p++ = *q++;
+               if (mp->state == MOD_UNINITIALIZED)
+                       q = "  (uninitialized)";
+               else if (mp->state == MOD_RUNNING)
+                       q = "";
+               else if (mp->state == MOD_DELETED)
+                       q = "  (deleted)";
+               else
+                       q = "  (bad state)";
+               while (*q)
+                       *p++ = *q++;
+               *p++ = '\n';
+       }
+       return p - buf;
+}
index 809329bb76a3c5d47dc568703bc1b2e2f338b3bd..cbf723484e47a5d4f3030bb1e1971cb610bda576 100644 (file)
@@ -126,7 +126,8 @@ sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
 sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
 sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
 sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
-sys_adjtimex, sys_mprotect, sys_sigprocmask };
+sys_adjtimex, sys_mprotect, sys_sigprocmask,
+sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms };
 
 /* So we don't have to do any more manual updating.... */
 int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
index ad022e16118c6ee8e26e770c03a64b17b21458e7..6cbaa15ff2a9bebfeeefb70531ff07b313f5a660 100644 (file)
@@ -25,6 +25,13 @@ struct vm_struct {
 
 static struct vm_struct * vmlist = NULL;
 
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
 #define VMALLOC_OFFSET (8*1024*1024)
 
 static inline void set_pgdir(unsigned long dindex, unsigned long value)