--- kernel/Makefile	Tue Jul 20 01:35:31 1993
+++ /usr/src/linux/kernel/Makefile	Sat Aug 28 13:02:41 1993
@@ -19,7 +19,7 @@
 SUBDIRS	= chr_drv blk_drv FPU-emu
 
 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
 
@@ -38,6 +38,10 @@
 
 sched.o: sched.c
 	$(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
+
+ksyms.o: ksyms.lst ksyms.sh
+	sh ksyms.sh > ksyms.s
+	$(AS) -o ksyms.o ksyms.s
 
 clean:
 	rm -f core *.o *.a *.s
--- kernel/chr_drv/mem.c	Mon Aug  9 18:02:32 1993
+++ /usr/src/linux/kernel/chr_drv/mem.c	Sat Aug 28 13:02:42 1993
@@ -366,6 +366,8 @@
 	NULL		/* fsync */
 };
 
+char* ftape_big_buffer;
+
 long chr_dev_init(long mem_start, long mem_end)
 {
 	if (register_chrdev(1,"mem",&memory_fops))
@@ -374,6 +376,17 @@
 	mem_start = lp_init(mem_start);
 	mem_start = mouse_init(mem_start);
 	mem_start = soundcard_init(mem_start);
+/*
+ *      Rude way to allocate kernel memory buffer for tape device
+ */
+#define NR_FTAPE_BUFFERS        3
+
+        printk( "ftape buffer (%d buffers) allocated at: %p\n",
+               NR_FTAPE_BUFFERS, mem_start);
+        ftape_big_buffer= (char*) mem_start;
+        /* 'n' 32Kb buffers+ alignment space */
+        mem_start+= NR_FTAPE_BUFFERS * 0x8000 + 0x7fff;
+
 #if CONFIG_TAPE_QIC02
 	mem_start = tape_qic02_init(mem_start);
 #endif
--- fs/devices.c	Wed Feb 17 19:20:50 1993
+++ /usr/src/linux/fs/devices.c	Sat Aug 28 13:02:42 1993
@@ -44,6 +44,17 @@
 }
 
 /*
+ * unregister function implemented for modules package (Bas L.)
+ */
+int unregister_chrdev( unsigned int major, const char * name)
+{
+	if (major >= MAX_CHRDEV || chrdev_fops[ major] == NULL)
+		return -EINVAL;
+	chrdev_fops[ major] = NULL;
+	return 0;
+}
+
+/*
  * Called every time a block special file is opened
  */
 int blkdev_open(struct inode * inode, struct file * filp)
--- fs/proc/array.c	Mon Aug  9 18:02:29 1993
+++ /usr/src/linux/fs/proc/array.c	Sat Aug 28 14:06:20 1993
@@ -300,6 +300,8 @@
 		       size, resident, share, trs, lrs, drs, dt);
 }
 
+int get_module_list( char *);
+
 static int array_read(struct inode * inode, struct file * file,char * buf, int count)
 {
 	char * page;
@@ -338,6 +340,9 @@
 			break;
 		case 12:
 			length = get_statm(pid, page);
+			break;
+		case 16:
+			length = get_module_list(page);
 			break;
 #ifdef CONFIG_DEBUG_MALLOC
 		case 13:
--- fs/proc/root.c	Mon Jul 12 22:09:24 1993
+++ /usr/src/linux/fs/proc/root.c	Sat Aug 28 13:03:25 1993
@@ -64,6 +64,7 @@
 #ifdef CONFIG_DEBUG_MALLOC
 	{13,6,"malloc" },
 #endif
+  	{ 16,7,"modules" }
 };
 
 #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
--- mm/memory.c	Sun Aug 15 11:09:18 1993
+++ /usr/src/linux/mm/memory.c	Sat Aug 28 13:02:42 1993
@@ -62,6 +62,8 @@
 
 unsigned short * mem_map = NULL;
 
+unsigned long *dload_pages;	/* for dynamic loading - KA */
+
 #define CODE_SPACE(addr,p) ((addr) < (p)->end_code)
 
 /*
@@ -1029,6 +1031,15 @@
 			address += PAGE_SIZE;
 		}
 	}
+	/*
+	 * Set up 4 MB of virtual address space for dynamicly loaded
+	 * kernel code.
+	 */
+	dload_pages = (unsigned long *) start_mem;
+	start_mem += 4096;
+	memset(dload_pages, 0, 4096);
+	swapper_pg_dir[800] = (unsigned long) dload_pages | PAGE_TABLE;
+
 	invalidate();
 	return start_mem;
 }
--- mm/swap.c	Sat Aug 14 15:59:34 1993
+++ /usr/src/linux/mm/swap.c	Sun Aug 29 14:39:09 1993
@@ -858,3 +858,68 @@
 	val->totalswap <<= PAGE_SHIFT;
 	return;
 }
+
+
+extern unsigned long *dload_pages;	/* set up in memory.c */
+
+/*
+ * Allocate a block of pages at contiguous virtual memory addresses.
+ * Used for dynamic loading of kernel modules.
+ */
+unsigned long ld_alloc_mem(int npages)
+{
+	int i;
+	int freecount;
+	int freeloc;
+	unsigned long page;
+
+	freecount = 0;
+	for (i = 0 ; i < 1024 ; i++) {
+		if (dload_pages[i] != 0) {
+			freecount = 0;
+		} else if (++freecount >= npages) {
+			break;
+		}
+	}
+	if (freecount < npages)
+		return 0;
+	freeloc = i + 1 - npages;
+	do {
+		dload_pages[i] = PAGE_RW;  /* mark page as taken */
+	} while (--i >= freeloc);
+	i += npages;
+	for (i = 0 ; i < npages ; i++) {
+		page = get_free_page(GFP_KERNEL);
+		if (page == 0)
+			goto bad;
+		dload_pages[freeloc + i] = page | PAGE_TABLE;
+	}
+	invalidate();
+	return (unsigned long)(freeloc + 32 * 1024) * 4096;
+
+bad:
+	for (i = 0 ; i < npages ; i++) {
+		page = dload_pages[freeloc + i];
+		if (page != PAGE_RW)
+			free_page(page);
+		dload_pages[freeloc + i] = 0;
+	}
+	return 0;
+}
+
+/*
+ * Free memory obtained from ld_alloc_mem.
+ */
+void ld_free_mem(unsigned long addr, int npages)
+{
+	int i;
+	int page;
+	int freeloc = (addr >> 12) - 32 * 1024;
+
+	for (i = 0 ; i < npages ; i++) {
+		page = dload_pages[freeloc + i];
+		free_page(page);
+		dload_pages[freeloc + i] = 0;
+	}
+
+}
--- include/linux/sys.h	Tue Jul 20 01:35:31 1993
+++ /usr/src/linux/include/linux/sys.h	Sat Aug 28 13:55:35 1993
@@ -130,6 +130,11 @@
 extern int sys_olduname();
 extern int sys_old_syscall();
 extern int sys_modify_ldt();
+extern int no_sys();
+extern int sys_create_module();
+extern int sys_init_module();
+extern int sys_delete_module();
+extern int sys_get_kernel_syms();
 
 /*
  * These are system calls that will be removed at some time
@@ -168,11 +173,18 @@
 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_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
+sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms,
+no_sys, no_sys, no_sys, no_sys, no_sys, no_sys};
 
 #ifdef __cplusplus
 }
 #endif
 
 /* So we don't have to do any more manual updating.... */
 int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
+
+
+
+
+
--- include/linux/fs.h	Wed Aug 11 22:52:45 1993
+++ /usr/src/linux/include/linux/fs.h	Sat Aug 28 15:12:24 1993
@@ -331,6 +331,7 @@
 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;
--- /dev/null	Sat Aug 29 21:48:28 1992
+++ /usr/src/linux/kernel/module.c	Sat Aug 28 14:05:08 1993
@@ -0,0 +1,264 @@
+#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>
+
+
+unsigned long ld_alloc_mem(int);
+void ld_free_mem(unsigned long, int);
+
+struct module *module_list = NULL;
+int freeing_modules;		/* true if some modules are marked for deletion */
+
+int get_mod_name( char *, char *);
+struct module *find_module( const char *);
+int free_modules( void);
+
+
+int
+no_sys(void)
+{
+	return -ENOSYS;
+}
+
+/*
+ * Allocate space for a module.
+ */
+int
+sys_create_module(char *module_name, unsigned long size)
+{
+	int npages;
+	unsigned long addr;
+	int len;
+	char name[MOD_MAX_NAME];
+	char *savename;
+	struct module *mp;
+	int error;
+
+	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 = ld_alloc_mem(npages)) == 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 created:  mp=0x%x, addr=0x%x\n",
+	       mp->name, mp, addr + sizeof (int));
+	return addr;
+}
+
+/*
+ * Initialize a module.
+ */
+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 ((error = get_mod_name(module_name, name)) != 0)
+		return error;
+	printk("init_module %s, codesize = %d, ", name, 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_module=0x%x, cleanup_module=0x%x\n", rt.init, rt.cleanup);
+	mp->cleanup = rt.cleanup;
+	if ((*rt.init)() != 0)
+		return -EBUSY;
+	mp->state = MOD_RUNNING;
+	return 0;
+}
+
+int
+sys_delete_module(char *module_name)
+{
+	struct module *mp;
+	char name[MOD_MAX_NAME];
+	int error;
+
+	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.
+ */
+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->state == MOD_DELETED || strcmp(mp->name, name) != 0) ;
+	     mp = mp->next);
+	return mp;
+}
+
+
+/*
+ * Try to free modules which have been marked for deletion.  Returns nonzero
+ * if a module was actually freed.
+ */
+int
+free_modules()
+{
+	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;
+			ld_free_mem(mp->addr, mp->size);
+			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;
+}
--- /dev/null	Sat Aug 29 21:48:28 1992
+++ /usr/src/linux/kernel/ksyms.lst	Sun Aug 29 14:40:17 1993
@@ -0,0 +1,146 @@
+_NR_syscalls
+_current
+_do_floppy
+_ftape_big_buffer
+_jiffies
+_jiffies_offset
+_memcpy
+_memmove
+_memset
+_memsetw
+_no_sys
+_printk
+_register_chrdev
+_schedule
+_startup_time
+_sys_access
+_sys_acct
+_sys_alarm
+_sys_break
+_sys_brk
+_sys_call_table
+_sys_chdir
+_sys_chmod
+_sys_chown
+_sys_chroot
+_sys_close
+_sys_creat
+_sys_create_module
+_sys_delete_module
+_sys_dup
+_sys_dup2
+_sys_execve
+_sys_exit
+_sys_fchmod
+_sys_fchown
+_sys_fcntl
+_sys_fork
+_sys_fstat
+_sys_fstatfs
+_sys_fsync
+_sys_ftime
+_sys_ftruncate
+_sys_get_kernel_syms
+_sys_getegid
+_sys_geteuid
+_sys_getgid
+_sys_getgroups
+_sys_getitimer
+_sys_getpgrp
+_sys_getpid
+_sys_getppid
+_sys_getpriority
+_sys_getrlimit
+_sys_getrusage
+_sys_gettimeofday
+_sys_getuid
+_sys_gtty
+_sys_idle
+_sys_init_module
+_sys_ioctl
+_sys_ioperm
+_sys_iopl
+_sys_ipc
+_sys_kill
+_sys_link
+_sys_lock
+_sys_lseek
+_sys_lstat
+_sys_mkdir
+_sys_mknod
+_sys_mmap
+_sys_modify_ldt
+_sys_mount
+_sys_mpx
+_sys_munmap
+_sys_newfstat
+_sys_newlstat
+_sys_newstat
+_sys_newuname
+_sys_nice
+_sys_olduname
+_sys_open
+_sys_pause
+_sys_phys
+_sys_pipe
+_sys_prof
+_sys_profil
+_sys_ptrace
+_sys_read
+_sys_readdir
+_sys_readlink
+_sys_reboot
+_sys_rename
+_sys_rmdir
+_sys_select
+_sys_setdomainname
+_sys_setgid
+_sys_setgroups
+_sys_sethostname
+_sys_setitimer
+_sys_setpgid
+_sys_setpriority
+_sys_setregid
+_sys_setreuid
+_sys_setrlimit
+_sys_setsid
+_sys_settimeofday
+_sys_setuid
+_sys_setup
+_sys_sgetmask
+_sys_sigaction
+_sys_signal
+_sys_sigpending
+_sys_sigreturn
+_sys_sigsuspend
+_sys_socketcall
+_sys_ssetmask
+_sys_stat
+_sys_statfs
+_sys_stime
+_sys_stty
+_sys_swapoff
+_sys_swapon
+_sys_symlink
+_sys_sync
+_sys_sysinfo
+_sys_syslog
+_sys_time
+_sys_times
+_sys_truncate
+_sys_ulimit
+_sys_umask
+_sys_umount
+_sys_uname
+_sys_unlink
+_sys_uselib
+_sys_ustat
+_sys_utime
+_sys_vhangup
+_sys_vm86
+_sys_wait4
+_sys_waitpid
+_sys_write
+_unregister_chrdev
+_verify_area
+_wake_up_interruptible
--- /dev/null	Sat Aug 29 21:48:28 1992
+++ /usr/src/linux/kernel/ksyms.sh	Sat Aug 28 13:02:43 1993
@@ -0,0 +1,25 @@
+# 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[];
+
+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 " $0; print "	.long strings+" stringloc; stringloc += length($0) + 1;}' ksyms.tmp
+echo '
+strings:'
+awk '{print "	.ascii \"" $0 "\\0\""}' ksyms.tmp
+rm ksyms.tmp
--- /dev/null	Sat Aug 29 21:48:28 1992
+++ /usr/src/linux/include/linux/module.h	Sat Aug 28 16:53:44 1993
@@ -0,0 +1,49 @@
+/*
+ * 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 */
+	unsigned long 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 */
+};
+
+
+/*
+ * The first word of the module contains the use count.
+ */
+#define GET_USE_COUNT(module)	(* (int *) (module)->addr)
+
+extern struct module *module_list;
+
+#endif
