summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /kernel
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile22
-rw-r--r--kernel/dma.c95
-rw-r--r--kernel/exec_domain.c2
-rw-r--r--kernel/exit.c47
-rw-r--r--kernel/fork.c175
-rw-r--r--kernel/itimer.c1
-rw-r--r--kernel/ksyms.c183
-rw-r--r--kernel/ksyms.ver194
-rw-r--r--kernel/module.c201
-rw-r--r--kernel/printk.c7
-rw-r--r--kernel/resource.c138
-rw-r--r--kernel/sched.c796
-rw-r--r--kernel/signal.c174
-rw-r--r--kernel/softirq.c55
-rw-r--r--kernel/sys.c114
-rw-r--r--kernel/time.c121
-rw-r--r--kernel/tqueue.c10
-rw-r--r--kernel/vsprintf.c309
18 files changed, 1928 insertions, 716 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 99ced21ae..fd73ad5f0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -12,24 +12,23 @@
.c.s:
$(CC) $(CFLAGS) -S $<
.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
+ $(AS) -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c $<
-OBJS = sched.o entry.o traps.o irq.o dma.o fork.o exec_domain.o \
- panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
- signal.o ptrace.o ioport.o itimer.o \
- info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o dummy.o
+OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
+ module.o exit.o signal.o itimer.o info.o time.o softirq.o \
+ resource.o
-all: kernel.o
+SYMTAB_OBJS = ksyms.o
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
- sync
+all: kernel.o
-entry.s: entry.S
+include ../versions.mk
-entry.o: entry.s
+kernel.o: $(SYMTAB_OBJS) $(OBJS)
+ $(LD) -r -o kernel.o $(SYMTAB_OBJS) $(OBJS)
+ sync
sched.o: sched.c
$(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
@@ -38,6 +37,7 @@ dep:
$(CPP) -M *.c > .depend
dummy:
+modules:
#
# include a dependency file if one exists
diff --git a/kernel/dma.c b/kernel/dma.c
index 799439ed6..94b121653 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -1,12 +1,19 @@
-/* $Id: dma.c,v 1.5 1992/11/18 02:49:05 root Exp root $
+/* $Id: dma.c,v 1.7 1994/12/28 03:35:33 root Exp root $
* linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
- * Written by Hennus Bergman, 1992.
+ *
+ * Written by Hennus Bergman, 1992.
+ *
+ * 1994/12/26: Changes by Alex Nash to fix a minor bug in /proc/dma.
+ * In the previous version the reported device could end up being wrong,
+ * if a device requested a DMA channel that was already in use.
+ * [It also happened to remove the sizeof(char *) == sizeof(int)
+ * assumption introduced because of those /proc/dma patches. -- Hennus]
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <asm/system.h>
#include <asm/dma.h>
+#include <asm/system.h>
/* A note on resource allocation:
@@ -16,7 +23,7 @@
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
- *
+ *
* So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.
* When releasing them, first release the DMA, then release the IRQ.
* If you don't, you may cause allocation requests to fail unnecessarily.
@@ -26,81 +33,52 @@
-/* Channel n is busy iff dma_chan_busy[n] != 0.
+/* Channel n is busy iff dma_chan_busy[n].lock != 0.
* DMA0 used to be reserved for DRAM refresh, but apparently not any more...
* DMA4 is reserved for cascading.
*/
-/*
-static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
- 0, 0, 0, 0, 1, 0, 0, 0
-};
-*/
-static volatile char * dma_chan_busy[MAX_DMA_CHANNELS] = {
- 0,
- 0,
- 0,
- 0,
- "cascade",
- 0,
- 0,
- 0
-};
-/* Atomically swap memory location [32 bits] with `newval'.
- * This avoid the cli()/sti() junk and related problems.
- * [And it's faster too :-)]
- * Maybe this should be in include/asm/mutex.h and be used for
- * implementing kernel-semaphores as well.
- */
-static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsigned int newval)
-{
- unsigned int semval = newval;
-
- /* If one of the operands for the XCHG instructions is a memory ref,
- * it makes the swap an uninterruptible RMW cycle.
- *
- * One operand must be in memory, the other in a register, otherwise
- * the swap may not be atomic.
- */
-
-#if 0
- asm __volatile__ ("xchgl %2, %0\n"
- : /* outputs: semval */ "=r" (semval)
- : /* inputs: newval, p */ "0" (semval), "m" (*p)
- ); /* p is a var, containing an address */
-#else
- /*
- * RB: Try atomic exchange from include/asm/system.h
- * This should be portable...
- */
- atomic_exchange(p,semval)
-#endif
- return semval;
-} /* mutex_atomic_swap */
+struct dma_chan {
+ int lock;
+ char *device_id;
+};
+static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 1, "cascade" },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+};
int get_dma_list(char *buf)
{
int i, len = 0;
for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
- if (dma_chan_busy[i]) {
+ if (dma_chan_busy[i].lock) {
len += sprintf(buf+len, "%2d: %s\n",
- i,
- dma_chan_busy[i]);
+ i,
+ dma_chan_busy[i].device_id);
}
}
return len;
-}
+} /* get_dma_list */
-int request_dma(unsigned int dmanr, char * deviceID)
+
+int request_dma(unsigned int dmanr, char * device_id)
{
if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL;
- if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], (unsigned int) deviceID) != 0)
+ if (xchg_u32(&dma_chan_busy[dmanr].lock, 1) != 0)
return -EBUSY;
+ dma_chan_busy[dmanr].device_id = device_id;
+
/* old flag was 0, now contains 1 to indicate busy */
return 0;
} /* request_dma */
@@ -113,10 +91,9 @@ void free_dma(unsigned int dmanr)
return;
}
- if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], 0) == 0) {
+ if (xchg_u32(&dma_chan_busy[dmanr].lock, 0) == 0) {
printk("Trying to free free DMA%d\n", dmanr);
return;
}
} /* free_dma */
-
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index c80423314..7f0114a46 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -1,7 +1,7 @@
#include <linux/personality.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
-
+#include <linux/mm.h>
static asmlinkage void no_lcall7(struct pt_regs * regs);
diff --git a/kernel/exit.c b/kernel/exit.c
index 3a48c5c23..59c0b075b 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -47,7 +47,7 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv)
if (!p || sig > 32)
return -EINVAL;
if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
- (current->euid != p->euid) && (current->uid != p->uid) && !suser())
+ (current->euid != p->euid) && (current->euid != p->uid) && !suser())
return -EPERM;
if (!sig)
return 0;
@@ -91,6 +91,7 @@ void release(struct task_struct * p)
}
for (i=1 ; i<NR_TASKS ; i++)
if (task[i] == p) {
+ nr_tasks--;
task[i] = NULL;
REMOVE_LINKS(p);
if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
@@ -354,38 +355,6 @@ static void forget_original_parent(struct task_struct * father)
}
}
-static void exit_mm(void)
-{
- struct vm_area_struct * mpnt;
-
- mpnt = current->mm->mmap;
- current->mm->mmap = NULL;
- while (mpnt) {
- struct vm_area_struct * next = mpnt->vm_next;
- if (mpnt->vm_ops && mpnt->vm_ops->close)
- mpnt->vm_ops->close(mpnt);
- if (mpnt->vm_inode)
- iput(mpnt->vm_inode);
- kfree(mpnt);
- mpnt = next;
- }
-
-#ifdef __i386__
- /* forget local segments */
- __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
- : /* no outputs */
- : "r" (0));
- current->tss.ldt = 0;
- if (current->ldt) {
- void * ldt = current->ldt;
- current->ldt = NULL;
- vfree(ldt);
- }
-#endif
-
- free_page_tables(current);
-}
-
static void exit_files(void)
{
int i;
@@ -412,11 +381,13 @@ NORET_TYPE void do_exit(long code)
intr_count = 0;
}
fake_volatile:
- if (current->semundo)
- sem_exit();
- exit_mm();
+ current->flags |= PF_EXITING;
+ sem_exit();
+ exit_mmap(current);
+ free_page_tables(current);
exit_files();
exit_fs();
+ exit_thread();
forget_original_parent(current);
/*
* Check to see if any process groups have become orphaned
@@ -508,7 +479,7 @@ asmlinkage int sys_exit(int error_code)
do_exit((error_code&0xff)<<8);
}
-asmlinkage int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
+asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
{
int flag, retval;
struct wait_queue wait = { current, NULL };
@@ -599,7 +570,7 @@ end_wait4:
* sys_waitpid() remains for compatibility. waitpid() should be
* implemented by calling sys_wait4() from libc.a.
*/
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
+asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
{
return sys_wait4(pid, stat_addr, options, NULL);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index ceb6e09c1..104ffea96 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -24,13 +24,8 @@
#include <asm/segment.h>
#include <asm/system.h>
-asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
-
-/* These should maybe be in <linux/tasks.h> */
-
-#define MAX_TASKS_PER_USER (NR_TASKS/2)
-#define MIN_TASKS_LEFT_FOR_ROOT 4
-
+int nr_tasks=1;
+int nr_running=1;
long last_pid=0;
static int find_empty_process(void)
@@ -59,7 +54,7 @@ repeat:
goto repeat;
}
if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT ||
- this_user_tasks > MAX_TASKS_PER_USER)
+ this_user_tasks > current->rlim[RLIMIT_NPROC].rlim_cur)
if (current->uid)
return -EAGAIN;
return free_task;
@@ -95,18 +90,26 @@ static int dup_mmap(struct task_struct * tsk)
p = &tsk->mm->mmap;
for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
- if (!tmp)
+ if (!tmp) {
+ exit_mmap(tsk);
return -ENOMEM;
+ }
*tmp = *mpnt;
tmp->vm_task = tsk;
tmp->vm_next = NULL;
- if (tmp->vm_inode)
+ if (tmp->vm_inode) {
tmp->vm_inode->i_count++;
+ /* insert tmp into the share list, just after mpnt */
+ tmp->vm_next_share->vm_prev_share = tmp;
+ mpnt->vm_next_share = tmp;
+ tmp->vm_prev_share = mpnt;
+ }
if (tmp->vm_ops && tmp->vm_ops->open)
tmp->vm_ops->open(tmp);
*p = tmp;
p = &tmp->vm_next;
}
+ build_mmap_avl(tsk);
return 0;
}
@@ -136,7 +139,6 @@ static void copy_files(unsigned long clone_flags, struct task_struct * p)
static int copy_mm(unsigned long clone_flags, struct task_struct * p)
{
if (clone_flags & COPYVM) {
- p->mm->swappable = 1;
p->mm->min_flt = p->mm->maj_flt = 0;
p->mm->cmin_flt = p->mm->cmaj_flt = 0;
if (copy_page_tables(p))
@@ -158,121 +160,25 @@ static void copy_fs(unsigned long clone_flags, struct task_struct * p)
}
/*
- * FIXME: This functions shouldn't be in this file
- */
-#if defined (__i386__)
-
-#define IS_CLONE (regs->orig_eax == __NR_clone)
-
-static unsigned long
-arch_clone(struct task_struct *p, int nr, unsigned long clone_flags
- struct pt_regs *regs)
-{
- struct pt_regs * childregs;
- int i;
-
- /*
- * set up new TSS
- */
- p->tss.es = KERNEL_DS;
- p->tss.cs = KERNEL_CS;
- p->tss.ss = KERNEL_DS;
- p->tss.ds = KERNEL_DS;
- p->tss.fs = USER_DS;
- p->tss.gs = KERNEL_DS;
- p->tss.ss0 = KERNEL_DS;
- p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
- p->tss.tr = _TSS(nr);
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
- p->tss.esp = (unsigned long) childregs;
- p->tss.eip = (unsigned long) ret_from_sys_call;
- *childregs = *regs;
- childregs->eax = 0;
- p->tss.back_link = 0;
- /*
- * iopl is always 0 for a new process
- */
- p->tss.eflags = regs->eflags & 0xffffcfff;
- if (IS_CLONE) {
- if (regs->ebx)
- childregs->esp = regs->ebx;
- clone_flags = regs->ecx;
- if (childregs->esp == regs->esp)
- clone_flags |= COPYVM;
- }
- p->tss.ldt = _LDT(nr);
- if (p->ldt) {
- p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (p->ldt != NULL)
- memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
- }
- p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
- for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
- p->tss.io_bitmap[i] = ~0;
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
-
- return clone_flags;
-}
-#elif defined (__mips__)
-
-#include <asm/mipsregs.h>
-
-#define IS_CLONE (regs->orig_reg2 == __NR_clone)
-
-static unsigned long
-arch_clone(struct task_struct *p, int nr, unsigned long clone_flags,
- struct pt_regs *regs)
-{
- struct pt_regs * childregs;
-
- /*
- * set up new TSS
- */
- p->tss.fs = KERNEL_DS;
- p->tss.ksp = p->kernel_stack_page + PAGE_SIZE;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
- p->tss.reg29 = (unsigned long) childregs; /* new sp */
- p->tss.cp0_epc = (unsigned long) ret_from_sys_call;
- *childregs = *regs;
- childregs->reg1 = 0;
- /*
- * New tasks loose permission to use the fpa. This accelerates task
- * switching for non fp programms, which true for the most programms.
- */
- p->tss.cp0_status = regs->cp0_status & ~ST0_CU0;
- if (IS_CLONE) {
- if (regs->reg2)
- childregs->reg29 = regs->reg2;
- clone_flags = regs->reg3;
- if (childregs->reg29 == regs->reg29)
- clone_flags |= COPYVM;
- }
-
- return clone_flags;
-}
-#endif
-
-/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in its entirety.
*/
-asmlinkage int sys_fork(struct pt_regs regs)
+int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
{
- struct task_struct *p;
int nr;
- unsigned long clone_flags = COPYVM | SIGCHLD;
+ unsigned long new_stack;
+ struct task_struct *p;
- /*
- * Clone the machine independend part of every process
- */
if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL)))
goto bad_fork;
+ new_stack = get_free_page(GFP_KERNEL);
+ if (!new_stack)
+ goto bad_fork_free;
nr = find_empty_process();
if (nr < 0)
goto bad_fork_free;
- task[nr] = p;
+
*p = *current;
if (p->exec_domain && p->exec_domain->use_count)
@@ -281,51 +187,36 @@ asmlinkage int sys_fork(struct pt_regs regs)
(*p->binfmt->use_count)++;
p->did_exec = 0;
- p->kernel_stack_page = 0;
+ p->kernel_stack_page = new_stack;
+ *(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
p->state = TASK_UNINTERRUPTIBLE;
p->flags &= ~(PF_PTRACED|PF_TRACESYS);
p->pid = last_pid;
p->p_pptr = p->p_opptr = current;
p->p_cptr = NULL;
- SET_LINKS(p);
p->signal = 0;
p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;
p->leader = 0; /* process leadership doesn't inherit */
+ p->tty_old_pgrp = 0;
p->utime = p->stime = 0;
p->cutime = p->cstime = 0;
p->start_time = jiffies;
+ p->mm->swappable = 0; /* don't try to swap it out before it's set up */
+ task[nr] = p;
+ SET_LINKS(p);
+ nr_tasks++;
- /*
- * set up new kernel stack
- */
- if (!(p->kernel_stack_page = get_free_page(GFP_KERNEL)))
- goto bad_fork_cleanup;
- *(unsigned long *)p->kernel_stack_page = STACK_MAGIC;
-
- /*
- * And now let's do the processor dependend things...
- */
-
- clone_flags = arch_clone(p, nr, clone_flags, &regs);
-
+ /* copy all the process information */
+ copy_thread(nr, clone_flags, usp, p, regs);
if (copy_mm(clone_flags, p))
goto bad_fork_cleanup;
p->semundo = NULL;
copy_files(clone_flags, p);
copy_fs(clone_flags, p);
-#if defined (__i386__)
- /*
- * May I move this into arch_clone without trouble, Linus???
- */
- set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
- if (p->ldt)
- set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
- else
- set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
-#endif
-
+ /* ok, now we should be set up.. */
+ p->mm->swappable = 1;
p->exit_signal = clone_flags & CSIGNAL;
p->counter = current->counter >> 1;
p->state = TASK_RUNNING; /* do this last, just in case */
@@ -333,10 +224,10 @@ asmlinkage int sys_fork(struct pt_regs regs)
bad_fork_cleanup:
task[nr] = NULL;
REMOVE_LINKS(p);
- free_page(p->kernel_stack_page);
+ nr_tasks--;
bad_fork_free:
+ free_page(new_stack);
free_page((long) p);
bad_fork:
return -EAGAIN;
}
-
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 4d5fa0f67..02f7b7ce8 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -11,6 +11,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/time.h>
+#include <linux/mm.h>
#include <asm/segment.h>
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index d13e3c4a4..ccb2f2b4c 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -3,11 +3,14 @@
* with dynamically loaded kernel modules.
* Jon.
*
- * Stacked module support and unified symbol table added by
- * Bjorn Ekwall <bj0rn@blox.se>
+ * - Stacked module support and unified symbol table added (June 1994)
+ * - External symbol table support added (December 1994)
+ * - Versions on symbols added (December 1994)
+ * by Bjorn Ekwall <bj0rn@blox.se>
*/
#include <linux/autoconf.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
@@ -22,7 +25,6 @@
#include <linux/timer.h>
#include <linux/binfmts.h>
#include <linux/personality.h>
-#include <linux/module.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
#include <linux/tty.h>
@@ -30,48 +32,90 @@
#include <linux/locks.h>
#include <linux/string.h>
#include <linux/delay.h>
-#ifdef CONFIG_INET
+#include <linux/config.h>
+
+#ifdef CONFIG_NET
#include <linux/net.h>
#include <linux/netdevice.h>
+#ifdef CONFIG_INET
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/arp.h>
+#include <net/tcp.h>
+#if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
+#include "../drivers/net/slhc.h"
+#endif
+#endif
+#endif
+#ifdef CONFIG_PCI
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#endif
+#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS)
+#include <linux/msdos_fs.h>
#endif
#include <asm/irq.h>
-extern char floppy_track_buffer[];
+
+extern char *floppy_track_buffer;
+
extern void set_device_ro(int dev,int flag);
-#include <linux/delay.h>
-#include <linux/locks.h>
+extern struct file_operations * get_blkfops(unsigned int);
extern void *sys_call_table;
-/* must match struct internal_symbol !!! */
-#define X(name) { (void *) &name, "_" #name }
-
#ifdef CONFIG_FTAPE
extern char * ftape_big_buffer;
-extern void (*do_floppy)(void);
+#endif
+
+#ifdef CONFIG_SCSI
+#include "../drivers/scsi/scsi.h"
+#include "../drivers/scsi/hosts.h"
+#include "../drivers/scsi/constants.h"
#endif
extern int sys_tz;
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
-extern int do_execve(char * filename, char ** argv, char ** envp,
- struct pt_regs * regs);
-extern int do_signal(unsigned long oldmask, struct pt_regs * regs);
-
+extern int close_fp(struct file *filp);
extern void (* iABI_hook)(struct pt_regs * regs);
-struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
- {
+struct symbol_table symbol_table = {
+#include <linux/symtab_begin.h>
+#ifdef CONFIG_MODVERSIONS
+ { (void *)1 /* Version version :-) */, "_Using_Versions" },
+#endif
/* stackable module support */
X(rename_module_symbol),
+ X(register_symtab),
/* system info variables */
+ /* These check that they aren't defines (0/1) */
+#ifndef EISA_bus__is_a_macro
X(EISA_bus),
-#ifdef __i386__
+#endif
+#ifndef MCA_bus__is_a_macro
+ X(MCA_bus),
+#endif
+#ifndef wp_works_ok__is_a_macro
X(wp_works_ok),
#endif
+#ifdef CONFIG_PCI
+ /* PCI BIOS support */
+ X(pcibios_present),
+ X(pcibios_find_class),
+ X(pcibios_find_device),
+ X(pcibios_read_config_byte),
+ X(pcibios_read_config_word),
+ X(pcibios_read_config_dword),
+ X(pcibios_strerror),
+ X(pcibios_write_config_byte),
+ X(pcibios_write_config_word),
+ X(pcibios_write_config_dword),
+#endif
+
/* process memory management */
X(verify_area),
X(do_mmap),
@@ -97,6 +141,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(namei),
X(lnamei),
X(open_namei),
+ X(close_fp),
X(check_disk_change),
X(invalidate_buffers),
X(fsync_dev),
@@ -107,9 +152,12 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(set_blocksize),
X(getblk),
X(bread),
+ X(breada),
X(brelse),
X(ll_rw_block),
X(__wait_on_buffer),
+ X(dcache_lookup),
+ X(dcache_add),
/* device registration */
X(register_chrdev),
@@ -126,17 +174,25 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(block_fsync),
X(wait_for_request),
X(blksize_size),
+ X(hardsect_size),
X(blk_size),
X(blk_dev),
X(is_read_only),
X(set_device_ro),
X(bmap),
X(sync_dev),
+ X(get_blkfops),
/* Module creation of serial units */
X(register_serial),
X(unregister_serial),
+ /* tty routines */
+ X(tty_hangup),
+ X(tty_wait_until_sent),
+ X(tty_check_change),
+ X(tty_hung_up_p),
+
/* filesystem registration */
X(register_filesystem),
X(unregister_filesystem),
@@ -161,6 +217,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(del_timer),
X(tq_timer),
X(tq_immediate),
+ X(tq_scheduler),
X(tq_last),
X(timer_active),
X(timer_table),
@@ -168,6 +225,15 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
/* dma handling */
X(request_dma),
X(free_dma),
+#ifdef HAVE_DISABLE_HLT
+ X(disable_hlt),
+ X(enable_hlt),
+#endif
+
+ /* IO port handling */
+ X(check_region),
+ X(request_region),
+ X(release_region),
/* process management */
X(wake_up),
@@ -198,7 +264,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(send_sig),
/* Program loader interfaces */
- X(change_ldt),
+ X(setup_arg_pages),
X(copy_strings),
X(create_tables),
X(do_execve),
@@ -208,16 +274,33 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
/* Miscellaneous access points */
X(si_meminfo),
-
+#ifdef CONFIG_NET
/* socket layer registration */
X(sock_register),
X(sock_unregister),
+ /* Internet layer registration */
+#ifdef CONFIG_INET
+ X(inet_add_protocol),
+ X(inet_del_protocol),
+#if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
+ /* VJ header compression */
+ X(slhc_init),
+ X(slhc_free),
+ X(slhc_remember),
+ X(slhc_compress),
+ X(slhc_uncompress),
+#endif
+#endif
+ /* Device callback registration */
+ X(register_netdevice_notifier),
+ X(unregister_netdevice_notifier),
+#endif
#ifdef CONFIG_FTAPE
/* The next labels are needed for ftape driver. */
X(ftape_big_buffer),
- X(do_floppy),
#endif
+ X(floppy_track_buffer),
#ifdef CONFIG_INET
/* support for loadable net drivers */
X(register_netdev),
@@ -226,7 +309,6 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(alloc_skb),
X(kfree_skb),
X(dev_kfree_skb),
- X(snarf_region),
X(netif_rx),
X(dev_rint),
X(dev_tint),
@@ -237,6 +319,31 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(dev_ioctl),
X(dev_queue_xmit),
X(dev_base),
+ X(dev_close),
+ X(arp_find),
+ X(n_tty_ioctl),
+ X(tty_register_ldisc),
+ X(kill_fasync),
+#endif
+#ifdef CONFIG_SCSI
+ /* Supports loadable scsi drivers */
+ /*
+ * in_scan_scsis is a hack, and should go away once the new
+ * memory allocation code is in the NCR driver
+ */
+ X(in_scan_scsis),
+ X(scsi_register_module),
+ X(scsi_unregister_module),
+ X(scsi_free),
+ X(scsi_malloc),
+ X(scsi_register),
+ X(scsi_unregister),
+ X(scsicam_bios_param),
+ X(scsi_init_malloc),
+ X(scsi_init_free),
+ X(print_command),
+ X(print_msg),
+ X(print_status),
#endif
/* Added to make file system as module */
X(set_writetime),
@@ -251,13 +358,39 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(chrdev_inode_operations),
X(blkdev_inode_operations),
X(read_ahead),
+ X(get_hash_table),
+ X(get_empty_inode),
+ X(insert_inode_hash),
+ X(event),
+ X(__down),
+#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS)
+ /* support for umsdos fs */
+ X(msdos_bmap),
+ X(msdos_create),
+ X(msdos_file_read),
+ X(msdos_file_write),
+ X(msdos_lookup),
+ X(msdos_mkdir),
+ X(msdos_mmap),
+ X(msdos_put_inode),
+ X(msdos_put_super),
+ X(msdos_read_inode),
+ X(msdos_read_super),
+ X(msdos_readdir),
+ X(msdos_rename),
+ X(msdos_rmdir),
+ X(msdos_smap),
+ X(msdos_statfs),
+ X(msdos_truncate),
+ X(msdos_unlink),
+ X(msdos_unlink_umsdos),
+ X(msdos_write_inode),
+#endif
/********************************************************
* Do not add anything below this line,
* as the stacked modules depend on this!
*/
- { NULL, NULL } /* mark end of table */
- },
- { { NULL, NULL } /* no module refs */ }
+#include <linux/symtab_end.h>
};
/*
diff --git a/kernel/ksyms.ver b/kernel/ksyms.ver
new file mode 100644
index 000000000..76537cd4c
--- /dev/null
+++ b/kernel/ksyms.ver
@@ -0,0 +1,194 @@
+/**** This file is generated by genksyms DO NOT EDIT! ****/
+#if defined(CONFIG_MODVERSIONS) && !defined(__GENKSYMS__)
+#ifndef _KSYMS_VER_
+#define _KSYMS_VER_
+#define rename_module_symbol _set_ver(rename_module_symbol, b81c73c1)
+#define register_symtab _set_ver(register_symtab, e910ea66)
+#define EISA_bus _set_ver(EISA_bus, 7e37737c)
+#define wp_works_ok _set_ver(wp_works_ok, f37f99e9)
+#define verify_area _set_ver(verify_area, 4cfda560)
+#define do_mmap _set_ver(do_mmap, 677e7ee1)
+#define do_munmap _set_ver(do_munmap, 6221f117)
+#define zeromap_page_range _set_ver(zeromap_page_range, 7c395a26)
+#define unmap_page_range _set_ver(unmap_page_range, 0110085f)
+#define insert_vm_struct _set_ver(insert_vm_struct, 1f4e4882)
+#define merge_segments _set_ver(merge_segments, 6854be5a)
+#define __get_free_pages _set_ver(__get_free_pages, 5243d78b)
+#define free_pages _set_ver(free_pages, 96448859)
+#define kmalloc _set_ver(kmalloc, d31fb2cb)
+#define kfree_s _set_ver(kfree_s, 1e72eb79)
+#define vmalloc _set_ver(vmalloc, 667f3e25)
+#define vfree _set_ver(vfree, 6df52add)
+#define getname _set_ver(getname, 81487159)
+#define putname _set_ver(putname, b19e8126)
+#define __iget _set_ver(__iget, ee2b6320)
+#define iput _set_ver(iput, 59241ced)
+#define namei _set_ver(namei, 00478bcd)
+#define lnamei _set_ver(lnamei, fcfddbb1)
+#define open_namei _set_ver(open_namei, 414b2b0f)
+#define close_fp _set_ver(close_fp, 1d4c15d8)
+#define check_disk_change _set_ver(check_disk_change, b66ed457)
+#define invalidate_buffers _set_ver(invalidate_buffers, c65255f1)
+#define fsync_dev _set_ver(fsync_dev, a221190d)
+#define permission _set_ver(permission, 0ebf7474)
+#define inode_setattr _set_ver(inode_setattr, 0c80a3c1)
+#define inode_change_ok _set_ver(inode_change_ok, 5d1cb326)
+#define generic_mmap _set_ver(generic_mmap, d4ff59f3)
+#define set_blocksize _set_ver(set_blocksize, f45fda38)
+#define getblk _set_ver(getblk, d40228ac)
+#define bread _set_ver(bread, c73bf0f0)
+#define breada _set_ver(breada, eb8e858c)
+#define brelse _set_ver(brelse, 4c27ac3d)
+#define ll_rw_block _set_ver(ll_rw_block, f3aa4dd3)
+#define __wait_on_buffer _set_ver(__wait_on_buffer, e8fcc968)
+#define dcache_lookup _set_ver(dcache_lookup, 83336566)
+#define dcache_add _set_ver(dcache_add, fe71f11e)
+#define register_chrdev _set_ver(register_chrdev, da99513f)
+#define unregister_chrdev _set_ver(unregister_chrdev, 61ea5ee8)
+#define register_blkdev _set_ver(register_blkdev, 4699a621)
+#define unregister_blkdev _set_ver(unregister_blkdev, d39bbca9)
+#define tty_register_driver _set_ver(tty_register_driver, fcc8591c)
+#define tty_unregister_driver _set_ver(tty_unregister_driver, c78132a8)
+#define tty_std_termios _set_ver(tty_std_termios, cf350678)
+#define block_read _set_ver(block_read, a7fe4f51)
+#define block_write _set_ver(block_write, 902674c9)
+#define block_fsync _set_ver(block_fsync, 182888d8)
+#define wait_for_request _set_ver(wait_for_request, 9ca2932e)
+#define blksize_size _set_ver(blksize_size, dea1eb55)
+#define hardsect_size _set_ver(hardsect_size, ed1ee14f)
+#define blk_size _set_ver(blk_size, f60b5398)
+#define blk_dev _set_ver(blk_dev, dbf5fdd4)
+#define is_read_only _set_ver(is_read_only, b0c5f83e)
+#define set_device_ro _set_ver(set_device_ro, 8fb69e13)
+#define bmap _set_ver(bmap, 73bb8bdd)
+#define sync_dev _set_ver(sync_dev, 9bca536d)
+#define get_blkfops _set_ver(get_blkfops, 83827791)
+#define register_serial _set_ver(register_serial, 3425f38c)
+#define unregister_serial _set_ver(unregister_serial, c013d717)
+#define tty_hangup _set_ver(tty_hangup, e3487df0)
+#define tty_wait_until_sent _set_ver(tty_wait_until_sent, da85d428)
+#define tty_check_change _set_ver(tty_check_change, 705eaab0)
+#define tty_hung_up_p _set_ver(tty_hung_up_p, f99ac1e4)
+#define register_filesystem _set_ver(register_filesystem, 1c7110ef)
+#define unregister_filesystem _set_ver(unregister_filesystem, 5e353af7)
+#define register_binfmt _set_ver(register_binfmt, 66ece706)
+#define unregister_binfmt _set_ver(unregister_binfmt, 41822618)
+#define lookup_exec_domain _set_ver(lookup_exec_domain, 32f10d48)
+#define register_exec_domain _set_ver(register_exec_domain, eda4711f)
+#define unregister_exec_domain _set_ver(unregister_exec_domain, 78ea447c)
+#define request_irq _set_ver(request_irq, 9e81629c)
+#define free_irq _set_ver(free_irq, f487dc0c)
+#define enable_irq _set_ver(enable_irq, 54e09f5f)
+#define disable_irq _set_ver(disable_irq, b4449c1f)
+#define bh_active _set_ver(bh_active, 98fb5ca1)
+#define bh_mask _set_ver(bh_mask, 1abf3d3f)
+#define add_timer _set_ver(add_timer, f13cb728)
+#define del_timer _set_ver(del_timer, c7aff713)
+#define tq_timer _set_ver(tq_timer, 46cf583e)
+#define tq_immediate _set_ver(tq_immediate, 46cf583e)
+#define tq_scheduler _set_ver(tq_scheduler, 46cf583e)
+#define tq_last _set_ver(tq_last, 457cf547)
+#define timer_active _set_ver(timer_active, 5a6747ee)
+#define timer_table _set_ver(timer_table, 9e03b650)
+#define request_dma _set_ver(request_dma, 2a687646)
+#define free_dma _set_ver(free_dma, 5d4b914c)
+#define disable_hlt _set_ver(disable_hlt, 794487ee)
+#define enable_hlt _set_ver(enable_hlt, 9c7077bd)
+#define check_region _set_ver(check_region, b91154fb)
+#define request_region _set_ver(request_region, 138b0a1e)
+#define release_region _set_ver(release_region, f41d6d31)
+#define wake_up _set_ver(wake_up, e8d71419)
+#define wake_up_interruptible _set_ver(wake_up_interruptible, 64c8cb92)
+#define sleep_on _set_ver(sleep_on, 67a00cee)
+#define interruptible_sleep_on _set_ver(interruptible_sleep_on, 6a5fc80d)
+#define schedule _set_ver(schedule, 01000e51)
+#define current _set_ver(current, fc1cb29b)
+#define jiffies _set_ver(jiffies, 2f7c7437)
+#define xtime _set_ver(xtime, e70c0be0)
+#define loops_per_sec _set_ver(loops_per_sec, 40a14192)
+#define need_resched _set_ver(need_resched, dfc016ea)
+#define kill_proc _set_ver(kill_proc, 911f760a)
+#define kill_pg _set_ver(kill_pg, 0a758a45)
+#define kill_sl _set_ver(kill_sl, 49625e94)
+#define panic _set_ver(panic, 400c0de3)
+#define printk _set_ver(printk, ad1148ba)
+#define sprintf _set_ver(sprintf, f9003107)
+#define vsprintf _set_ver(vsprintf, e605cb6b)
+#define simple_strtoul _set_ver(simple_strtoul, bdb8c1e3)
+#define system_utsname _set_ver(system_utsname, 066845bc)
+#define sys_call_table _set_ver(sys_call_table, 79fa4011)
+#define do_signal _set_ver(do_signal, 86f9bc59)
+#define send_sig _set_ver(send_sig, 5cddd8d9)
+#define setup_arg_pages _set_ver(setup_arg_pages, fe68d94a)
+#define copy_strings _set_ver(copy_strings, 232aee96)
+#define create_tables _set_ver(create_tables, ba788fa2)
+#define do_execve _set_ver(do_execve, 8c99dc0a)
+#define flush_old_exec _set_ver(flush_old_exec, c737e178)
+#define open_inode _set_ver(open_inode, 27302cb6)
+#define read_exec _set_ver(read_exec, a80a2dd0)
+#define si_meminfo _set_ver(si_meminfo, bb05fc9a)
+#define sock_register _set_ver(sock_register, d68e1649)
+#define sock_unregister _set_ver(sock_unregister, 72c332bd)
+#define inet_add_protocol _set_ver(inet_add_protocol, 55292121)
+#define inet_del_protocol _set_ver(inet_del_protocol, 73908a1b)
+#define slhc_init _set_ver(slhc_init, e490a4b8)
+#define slhc_free _set_ver(slhc_free, 39ab902b)
+#define slhc_remember _set_ver(slhc_remember, db333be6)
+#define slhc_compress _set_ver(slhc_compress, e753e2d2)
+#define slhc_uncompress _set_ver(slhc_uncompress, 81cc1144)
+#define register_netdevice_notifier _set_ver(register_netdevice_notifier, e7aace7c)
+#define unregister_netdevice_notifier _set_ver(unregister_netdevice_notifier, be114416)
+#define floppy_track_buffer _set_ver(floppy_track_buffer, c6e3f7c2)
+#define register_netdev _set_ver(register_netdev, 0d8d1bb4)
+#define unregister_netdev _set_ver(unregister_netdev, 25a99579)
+#define ether_setup _set_ver(ether_setup, 4eafef91)
+#define alloc_skb _set_ver(alloc_skb, b6b523ba)
+#define kfree_skb _set_ver(kfree_skb, 0b938572)
+#define dev_kfree_skb _set_ver(dev_kfree_skb, aa1fe7f4)
+#define netif_rx _set_ver(netif_rx, d8051cb2)
+#define dev_rint _set_ver(dev_rint, 040d3f4b)
+#define dev_tint _set_ver(dev_tint, 860b350b)
+#define irq2dev_map _set_ver(irq2dev_map, 10bdcd8a)
+#define dev_add_pack _set_ver(dev_add_pack, 6d7d9be4)
+#define dev_remove_pack _set_ver(dev_remove_pack, 784fa59f)
+#define dev_get _set_ver(dev_get, 72ed90fd)
+#define dev_ioctl _set_ver(dev_ioctl, 08760203)
+#define dev_queue_xmit _set_ver(dev_queue_xmit, 4a478225)
+#define dev_base _set_ver(dev_base, 0a8809f0)
+#define dev_close _set_ver(dev_close, 9bdad56d)
+#define arp_find _set_ver(arp_find, a141bd11)
+#define n_tty_ioctl _set_ver(n_tty_ioctl, 538e5fa6)
+#define tty_register_ldisc _set_ver(tty_register_ldisc, 8fdde939)
+#define kill_fasync _set_ver(kill_fasync, 890501b6)
+#define in_scan_scsis _set_ver(in_scan_scsis, 21874a88)
+#define scsi_register_module _set_ver(scsi_register_module, 8eff1010)
+#define scsi_unregister_module _set_ver(scsi_unregister_module, d913b8f0)
+#define scsi_free _set_ver(scsi_free, 475dddfa)
+#define scsi_malloc _set_ver(scsi_malloc, 1cce3f92)
+#define scsi_register _set_ver(scsi_register, d6e77069)
+#define scsi_unregister _set_ver(scsi_unregister, 3b0b616b)
+#define scsicam_bios_param _set_ver(scsicam_bios_param, 3d965248)
+#define scsi_init_malloc _set_ver(scsi_init_malloc, e5167cbc)
+#define scsi_init_free _set_ver(scsi_init_free, 8b2721f8)
+#define print_command _set_ver(print_command, 6f14cd75)
+#define print_msg _set_ver(print_msg, 0465f877)
+#define print_status _set_ver(print_status, 32f84646)
+#define set_writetime _set_ver(set_writetime, 52131916)
+#define sys_tz _set_ver(sys_tz, aa3c9782)
+#define __wait_on_super _set_ver(__wait_on_super, 61a5c00a)
+#define file_fsync _set_ver(file_fsync, d30a190f)
+#define clear_inode _set_ver(clear_inode, da2b0e9f)
+#define refile_buffer _set_ver(refile_buffer, 8c69e123)
+#define ___strtok _set_ver(___strtok, 8b55d69c)
+#define init_fifo _set_ver(init_fifo, 082629c7)
+#define super_blocks _set_ver(super_blocks, e1f1ee99)
+#define chrdev_inode_operations _set_ver(chrdev_inode_operations, 6ba1faa3)
+#define blkdev_inode_operations _set_ver(blkdev_inode_operations, ed443696)
+#define read_ahead _set_ver(read_ahead, bbcd3768)
+#define get_hash_table _set_ver(get_hash_table, 3b5f3c55)
+#define get_empty_inode _set_ver(get_empty_inode, 554bdc75)
+#define insert_inode_hash _set_ver(insert_inode_hash, 59b8c371)
+#define event _set_ver(event, a6aac9c1)
+#define __down _set_ver(__down, 75aa9e96)
+#endif /* _KSYMS_VER_ */
+#endif /* CONFIG_MODVERSIONS !__GENKSYMS__ */
diff --git a/kernel/module.c b/kernel/module.c
index eb3ca2417..e29a48ba5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -23,6 +23,17 @@
* - Supports redefines of all symbols, for streams-like behaviour.
* - Compatible with older versions of insmod.
*
+ * New addition in December 1994: (Bjorn Ekwall, idea from Jacques Gelinas)
+ * - Externally callable function:
+ *
+ * "int register_symtab(struct symbol_table *)"
+ *
+ * This function can be called from within the kernel,
+ * and ALSO from loadable modules.
+ * The goal is to assist in modularizing the kernel even more,
+ * and finally: reducing the number of entries in ksyms.c
+ * since every subsystem should now be able to decide and
+ * control exactly what symbols it wants to export, locally!
*/
#ifdef DEBUG_MODULE
@@ -40,6 +51,7 @@ static struct module *find_module( const char *name);
static int get_mod_name( char *user_name, char *buf);
static int free_modules( void);
+static int module_init_flag = 0; /* Hmm... */
/*
* Called at boot time
@@ -117,7 +129,7 @@ rename_module_symbol(char *old_name, char *new_name)
/*
* Allocate space for a module.
*/
-asmlinkage int
+asmlinkage unsigned long
sys_create_module(char *module_name, unsigned long size)
{
struct module *mp;
@@ -162,7 +174,7 @@ sys_create_module(char *module_name, unsigned long size)
PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
mp->name, (unsigned long) mp->size, (unsigned long) mp->addr));
- return (int) addr;
+ return (unsigned long) addr;
}
/*
@@ -248,7 +260,7 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
/* relocate name pointers, index referred from start of table */
for (sym = &(newtab->symbol[0]), i = 0;
i < newtab->n_symbols; ++sym, ++i) {
- if ((int)sym->name < legal_start || size <= (int)sym->name) {
+ if ((unsigned long)sym->name < legal_start || size <= (unsigned long)sym->name) {
printk("Illegal symbol table! Rejected!\n");
kfree_s(newtab, size);
return -EINVAL;
@@ -285,8 +297,12 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
}
}
- if ((*rt.init)() != 0)
+ module_init_flag = 1; /* Hmm... */
+ if ((*rt.init)() != 0) {
+ module_init_flag = 0; /* Hmm... */
return -EBUSY;
+ }
+ module_init_flag = 0; /* Hmm... */
mp->state = MOD_RUNNING;
return 0;
@@ -354,6 +370,9 @@ sys_get_kernel_syms(struct kernel_sym *table)
/* include the count for the module name! */
nmodsyms += mp->symtab->n_symbols + 1;
}
+ else
+ /* include the count for the module name! */
+ nmodsyms += 1; /* return modules without symbols too */
}
if (table != NULL) {
@@ -364,21 +383,22 @@ sys_get_kernel_syms(struct kernel_sym *table)
/* copy all module symbols first (always LIFO order) */
for (mp = module_list; mp; mp = mp->next) {
- if ((mp->state == MOD_RUNNING) &&
- (mp->symtab != NULL) && (mp->symtab->n_symbols > 0)) {
+ if (mp->state == MOD_RUNNING) {
/* magic: write module info as a pseudo symbol */
isym.value = (unsigned long)mp;
sprintf(isym.name, "#%s", mp->name);
memcpy_tofs(to, &isym, sizeof isym);
++to;
- for (i = mp->symtab->n_symbols,
- from = mp->symtab->symbol;
- i > 0; --i, ++from, ++to) {
+ if (mp->symtab != NULL) {
+ for (i = mp->symtab->n_symbols,
+ from = mp->symtab->symbol;
+ i > 0; --i, ++from, ++to) {
- isym.value = (unsigned long)from->addr;
- strncpy(isym.name, from->name, sizeof isym.name);
- memcpy_tofs(to, &isym, sizeof isym);
+ isym.value = (unsigned long)from->addr;
+ strncpy(isym.name, from->name, sizeof isym.name);
+ memcpy_tofs(to, &isym, sizeof isym);
+ }
}
}
}
@@ -582,3 +602,160 @@ int get_ksyms_list(char *buf)
return p - buf;
}
+
+/*
+ * Rules:
+ * - The new symbol table should be statically allocated, or else you _have_
+ * to set the "size" field of the struct to the number of bytes allocated.
+ *
+ * - The strings that name the symbols will not be copied, maybe the pointers
+ *
+ * - For a loadable module, the function should only be called in the
+ * context of init_module
+ *
+ * Those are the only restrictions! (apart from not being reenterable...)
+ *
+ * If you want to remove a symbol table for a loadable module,
+ * the call looks like: "register_symtab(0)".
+ *
+ * The look of the code is mostly dictated by the format of
+ * the frozen struct symbol_table, due to compatibility demands.
+ */
+#define INTSIZ sizeof(struct internal_symbol)
+#define REFSIZ sizeof(struct module_ref)
+#define SYMSIZ sizeof(struct symbol_table)
+#define MODSIZ sizeof(struct module)
+static struct symbol_table nulltab;
+
+int
+register_symtab(struct symbol_table *intab)
+{
+ struct module *mp;
+ struct module *link;
+ struct symbol_table *oldtab;
+ struct symbol_table *newtab;
+ struct module_ref *newref;
+ int size;
+
+ if (intab && (intab->n_symbols == 0)) {
+ struct internal_symbol *sym;
+ /* How many symbols, really? */
+
+ for (sym = intab->symbol; sym->name; ++sym)
+ intab->n_symbols +=1;
+ }
+
+#if 1
+ if (module_init_flag == 0) { /* Hmm... */
+#else
+ if (module_list == &kernel_module) {
+#endif
+ /* Aha! Called from an "internal" module */
+ if (!intab)
+ return 0; /* or -ESILLY_PROGRAMMER :-) */
+
+ /* create a pseudo module! */
+ if (!(mp = (struct module*) kmalloc(MODSIZ, GFP_KERNEL))) {
+ /* panic time! */
+ printk("Out of memory for new symbol table!\n");
+ return -ENOMEM;
+ }
+ /* else OK */
+ memset(mp, 0, MODSIZ);
+ mp->state = MOD_RUNNING; /* Since it is resident... */
+ mp->name = ""; /* This is still the "kernel" symbol table! */
+ mp->symtab = intab;
+
+ /* link it in _after_ the resident symbol table */
+ mp->next = kernel_module.next;
+ kernel_module.next = mp;
+
+ return 0;
+ }
+
+ /* else ******** Called from a loadable module **********/
+
+ /*
+ * This call should _only_ be done in the context of the
+ * call to init_module i.e. when loading the module!!
+ * Or else...
+ */
+ mp = module_list; /* true when doing init_module! */
+
+ /* Any table there before? */
+ if ((oldtab = mp->symtab) == (struct symbol_table*)0) {
+ /* No, just insert it! */
+ mp->symtab = intab;
+ return 0;
+ }
+
+ /* else ****** we have to replace the module symbol table ******/
+#if 0
+ if (oldtab->n_symbols > 0) {
+ /* Oh dear, I have to drop the old ones... */
+ printk("Warning, dropping old symbols\n");
+ }
+#endif
+
+ if (oldtab->n_refs == 0) { /* no problems! */
+ mp->symtab = intab;
+ /* if the old table was kmalloc-ed, drop it */
+ if (oldtab->size > 0)
+ kfree_s(oldtab, oldtab->size);
+
+ return 0;
+ }
+
+ /* else */
+ /***** The module references other modules... insmod said so! *****/
+ /* We have to allocate a new symbol table, or we lose them! */
+ if (intab == (struct symbol_table*)0)
+ intab = &nulltab; /* easier code with zeroes in place */
+
+ /* the input symbol table space does not include the string table */
+ /* (it does for symbol tables that insmod creates) */
+
+ if (!(newtab = (struct symbol_table*)kmalloc(
+ size = SYMSIZ + intab->n_symbols * INTSIZ +
+ oldtab->n_refs * REFSIZ,
+ GFP_KERNEL))) {
+ /* panic time! */
+ printk("Out of memory for new symbol table!\n");
+ return -ENOMEM;
+ }
+
+ /* copy up to, and including, the new symbols */
+ memcpy(newtab, intab, SYMSIZ + intab->n_symbols * INTSIZ);
+
+ newtab->size = size;
+ newtab->n_refs = oldtab->n_refs;
+
+ /* copy references */
+ memcpy( ((char *)newtab) + SYMSIZ + intab->n_symbols * INTSIZ,
+ ((char *)oldtab) + SYMSIZ + oldtab->n_symbols * INTSIZ,
+ oldtab->n_refs * REFSIZ);
+
+ /* relink references from the old table to the new one */
+
+ /* pointer to the first reference entry in newtab! Really! */
+ newref = (struct module_ref*) &(newtab->symbol[newtab->n_symbols]);
+
+ /* check for reference links from previous modules */
+ for ( link = module_list;
+ link && (link != &kernel_module);
+ link = link->next) {
+
+ if (link->ref && (link->ref->module == mp))
+ link->ref = newref++;
+ }
+
+ mp->symtab = newtab;
+
+ /* all references (if any) have been handled */
+
+ /* if the old table was kmalloc-ed, drop it */
+ if (oldtab->size > 0)
+ kfree_s(oldtab, oldtab->size);
+
+ return 0;
+}
diff --git a/kernel/printk.c b/kernel/printk.c
index d92269b30..8b518f6cb 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
#define LOG_BUF_LEN 4096
@@ -129,7 +130,7 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
return 0;
case 8:
- if (len < 0 || len > 8)
+ if (len < 1 || len > 8)
return -EINVAL;
console_loglevel = len;
return 0;
@@ -173,8 +174,10 @@ asmlinkage int printk(const char *fmt, ...)
log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
if (log_size < LOG_BUF_LEN)
log_size++;
- else
+ else {
log_start++;
+ log_start &= LOG_BUF_LEN-1;
+ }
logged_chars++;
if (*p == '\n')
break;
diff --git a/kernel/resource.c b/kernel/resource.c
new file mode 100644
index 000000000..5a7999d73
--- /dev/null
+++ b/kernel/resource.c
@@ -0,0 +1,138 @@
+/*
+ * linux/kernel/resource.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * David Hinds
+ *
+ * Kernel io-region resource management
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+#define IOTABLE_SIZE 64
+
+typedef struct resource_entry_t {
+ u_long from, num;
+ const char *name;
+ struct resource_entry_t *next;
+} resource_entry_t;
+
+static resource_entry_t iolist = { 0, 0, "", NULL };
+
+static resource_entry_t iotable[IOTABLE_SIZE];
+
+/*
+ * This generates the report for /proc/ioports
+ */
+int get_ioport_list(char *buf)
+{
+ resource_entry_t *p;
+ int len = 0;
+
+ for (p = iolist.next; (p) && (len < 4000); p = p->next)
+ len += sprintf(buf+len, "%04lx-%04lx : %s\n",
+ p->from, p->from+p->num-1, p->name);
+ if (p)
+ len += sprintf(buf+len, "4K limit reached!\n");
+ return len;
+}
+
+/*
+ * The workhorse function: find where to put a new entry
+ */
+static resource_entry_t *find_gap(resource_entry_t *root,
+ u_long from, u_long num)
+{
+ unsigned long flags;
+ resource_entry_t *p;
+
+ if (from > from+num-1)
+ return NULL;
+ save_flags(flags);
+ cli();
+ for (p = root; ; p = p->next) {
+ if ((p != root) && (p->from+p->num-1 >= from)) {
+ p = NULL;
+ break;
+ }
+ if ((p->next == NULL) || (p->next->from > from+num-1))
+ break;
+ }
+ restore_flags(flags);
+ return p;
+}
+
+/*
+ * Call this from the device driver to register the ioport region.
+ */
+void request_region(unsigned int from, unsigned int num, const char *name)
+{
+ resource_entry_t *p;
+ int i;
+
+ for (i = 0; i < IOTABLE_SIZE; i++)
+ if (iotable[i].num == 0)
+ break;
+ if (i == IOTABLE_SIZE)
+ printk("warning: ioport table is full\n");
+ else {
+ p = find_gap(&iolist, from, num);
+ if (p == NULL)
+ return;
+ iotable[i].name = name;
+ iotable[i].from = from;
+ iotable[i].num = num;
+ iotable[i].next = p->next;
+ p->next = &iotable[i];
+ return;
+ }
+}
+
+/*
+ * This is for compatibility with older drivers.
+ * It can be removed when all drivers call the new function.
+ */
+void snarf_region(unsigned int from, unsigned int num)
+{
+ request_region(from,num,"No name given.");
+}
+
+/*
+ * Call this when the device driver is unloaded
+ */
+void release_region(unsigned int from, unsigned int num)
+{
+ resource_entry_t *p, *q;
+
+ for (p = &iolist; ; p = q) {
+ q = p->next;
+ if (q == NULL)
+ break;
+ if ((q->from == from) && (q->num == num)) {
+ q->num = 0;
+ p->next = q->next;
+ return;
+ }
+ }
+}
+
+/*
+ * Call this to check the ioport region before probing
+ */
+int check_region(unsigned int from, unsigned int num)
+{
+ return (find_gap(&iolist, from, num) == NULL) ? -EBUSY : 0;
+}
+
+/* Called from init/main.c to reserve IO ports. */
+void reserve_setup(char *str, int *ints)
+{
+ int i;
+
+ for (i = 1; i < ints[0]; i += 2)
+ request_region(ints[i], ints[i+1], "reserved");
+}
diff --git a/kernel/sched.c b/kernel/sched.c
new file mode 100644
index 000000000..93003dfc1
--- /dev/null
+++ b/kernel/sched.c
@@ -0,0 +1,796 @@
+/*
+ * linux/kernel/sched.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * 'sched.c' is the main kernel file. It contains scheduling primitives
+ * (sleep_on, wakeup, schedule etc) as well as a number of simple system
+ * call functions (type getpid(), which just extracts a field from
+ * current-task
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/fdreg.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/resource.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+
+#define TIMER_IRQ 0
+
+#include <linux/timex.h>
+
+/*
+ * kernel variables
+ */
+long tick = 1000000 / HZ; /* timer interrupt period */
+volatile struct timeval xtime; /* The current time */
+int tickadj = 500/HZ; /* microsecs */
+
+DECLARE_TASK_QUEUE(tq_timer);
+DECLARE_TASK_QUEUE(tq_immediate);
+DECLARE_TASK_QUEUE(tq_scheduler);
+
+/*
+ * phase-lock loop variables
+ */
+int time_status = TIME_BAD; /* clock synchronization status */
+long time_offset = 0; /* time adjustment (us) */
+long time_constant = 0; /* pll time constant */
+long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
+long time_precision = 1; /* clock precision (us) */
+long time_maxerror = 0x70000000;/* maximum error */
+long time_esterror = 0x70000000;/* estimated error */
+long time_phase = 0; /* phase offset (scaled us) */
+long time_freq = 0; /* frequency offset (scaled ppm) */
+long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
+long time_reftime = 0; /* time at last adjustment (s) */
+
+long time_adjust = 0;
+long time_adjust_step = 0;
+
+int need_resched = 0;
+unsigned long event = 0;
+
+extern int _setitimer(int, struct itimerval *, struct itimerval *);
+unsigned long * prof_buffer = NULL;
+unsigned long prof_len = 0;
+
+#define _S(nr) (1<<((nr)-1))
+
+extern void mem_use(void);
+
+extern int timer_interrupt(void);
+
+unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+struct task_struct init_task = INIT_TASK;
+
+unsigned long volatile jiffies=0;
+
+struct task_struct *current = &init_task;
+struct task_struct *last_task_used_math = NULL;
+
+struct task_struct * task[NR_TASKS] = {&init_task, };
+
+struct kernel_stat kstat = { 0 };
+
+unsigned long itimer_ticks = 0;
+unsigned long itimer_next = ~0;
+
+/*
+ * 'schedule()' is the scheduler function. It's a very simple and nice
+ * scheduler: it's not perfect, but certainly works for most things.
+ * The one thing you might take a look at is the signal-handler code here.
+ *
+ * NOTE!! Task 0 is the 'idle' task, which gets called when no other
+ * tasks can run. It can not be killed, and it cannot sleep. The 'state'
+ * information in task[0] is never used.
+ *
+ * The "confuse_gcc" goto is used only to get better assembly code..
+ * Dijkstra probably hates me.
+ */
+asmlinkage void schedule(void)
+{
+ int c;
+ struct task_struct * p;
+ struct task_struct * next;
+ unsigned long ticks;
+
+/* check alarm, wake up any interruptible tasks that have got a signal */
+
+ if (intr_count) {
+ printk("Aiee: scheduling in interrupt\n");
+ intr_count = 0;
+ }
+ run_task_queue(&tq_scheduler);
+ cli();
+ ticks = itimer_ticks;
+ itimer_ticks = 0;
+ itimer_next = ~0;
+ sti();
+ need_resched = 0;
+ nr_running = 0;
+ p = &init_task;
+ for (;;) {
+ if ((p = p->next_task) == &init_task)
+ goto confuse_gcc1;
+ if (ticks && p->it_real_value) {
+ if (p->it_real_value <= ticks) {
+ send_sig(SIGALRM, p, 1);
+ if (!p->it_real_incr) {
+ p->it_real_value = 0;
+ goto end_itimer;
+ }
+ do {
+ p->it_real_value += p->it_real_incr;
+ } while (p->it_real_value <= ticks);
+ }
+ p->it_real_value -= ticks;
+ if (p->it_real_value < itimer_next)
+ itimer_next = p->it_real_value;
+ }
+end_itimer:
+ if (p->state != TASK_INTERRUPTIBLE)
+ continue;
+ if (p->signal & ~p->blocked) {
+ p->state = TASK_RUNNING;
+ continue;
+ }
+ if (p->timeout && p->timeout <= jiffies) {
+ p->timeout = 0;
+ p->state = TASK_RUNNING;
+ }
+ }
+confuse_gcc1:
+
+/* this is the scheduler proper: */
+#if 0
+ /* give processes that go to sleep a bit higher priority.. */
+ /* This depends on the values for TASK_XXX */
+ /* This gives smoother scheduling for some things, but */
+ /* can be very unfair under some circumstances, so.. */
+ if (TASK_UNINTERRUPTIBLE >= (unsigned) current->state &&
+ current->counter < current->priority*2) {
+ ++current->counter;
+ }
+#endif
+ c = -1000;
+ next = p = &init_task;
+ for (;;) {
+ if ((p = p->next_task) == &init_task)
+ goto confuse_gcc2;
+ if (p->state == TASK_RUNNING) {
+ nr_running++;
+ if (p->counter > c)
+ c = p->counter, next = p;
+ }
+ }
+confuse_gcc2:
+ if (!c) {
+ for_each_task(p)
+ p->counter = (p->counter >> 1) + p->priority;
+ }
+ if (current == next)
+ return;
+ kstat.context_swtch++;
+
+ switch_to(next);
+}
+
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+/*
+ * wake_up doesn't wake up stopped processes - they have to be awakened
+ * with signals or similar.
+ *
+ * Note that this doesn't need cli-sti pairs: interrupts may not change
+ * the wait-queue structures directly, but only call wake_up() to wake
+ * a process. The process itself must remove the queue once it has woken.
+ */
+void wake_up(struct wait_queue **q)
+{
+ struct wait_queue *tmp;
+ struct task_struct * p;
+
+ if (!q || !(tmp = *q))
+ return;
+ do {
+ if ((p = tmp->task) != NULL) {
+ if ((p->state == TASK_UNINTERRUPTIBLE) ||
+ (p->state == TASK_INTERRUPTIBLE)) {
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter + 3)
+ need_resched = 1;
+ }
+ }
+ if (!tmp->next) {
+ printk("wait_queue is bad (eip = %p)\n",
+ __builtin_return_address(0));
+ printk(" q = %p\n",q);
+ printk(" *q = %p\n",*q);
+ printk(" tmp = %p\n",tmp);
+ break;
+ }
+ tmp = tmp->next;
+ } while (tmp != *q);
+}
+
+void wake_up_interruptible(struct wait_queue **q)
+{
+ struct wait_queue *tmp;
+ struct task_struct * p;
+
+ if (!q || !(tmp = *q))
+ return;
+ do {
+ if ((p = tmp->task) != NULL) {
+ if (p->state == TASK_INTERRUPTIBLE) {
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter + 3)
+ need_resched = 1;
+ }
+ }
+ if (!tmp->next) {
+ printk("wait_queue is bad (eip = %p)\n",
+ __builtin_return_address(0));
+ printk(" q = %p\n",q);
+ printk(" *q = %p\n",*q);
+ printk(" tmp = %p\n",tmp);
+ break;
+ }
+ tmp = tmp->next;
+ } while (tmp != *q);
+}
+
+void __down(struct semaphore * sem)
+{
+ struct wait_queue wait = { current, NULL };
+ add_wait_queue(&sem->wait, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ while (sem->count <= 0) {
+ schedule();
+ current->state = TASK_UNINTERRUPTIBLE;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&sem->wait, &wait);
+}
+
+static inline void __sleep_on(struct wait_queue **p, int state)
+{
+ unsigned long flags;
+ struct wait_queue wait = { current, NULL };
+
+ if (!p)
+ return;
+ if (current == task[0])
+ panic("task[0] trying to sleep");
+ current->state = state;
+ add_wait_queue(p, &wait);
+ save_flags(flags);
+ sti();
+ schedule();
+ remove_wait_queue(p, &wait);
+ restore_flags(flags);
+}
+
+void interruptible_sleep_on(struct wait_queue **p)
+{
+ __sleep_on(p,TASK_INTERRUPTIBLE);
+}
+
+void sleep_on(struct wait_queue **p)
+{
+ __sleep_on(p,TASK_UNINTERRUPTIBLE);
+}
+
+/*
+ * The head for the timer-list has a "expires" field of MAX_UINT,
+ * and the sorting routine counts on this..
+ */
+static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
+#define SLOW_BUT_DEBUGGING_TIMERS 1
+
+void add_timer(struct timer_list * timer)
+{
+ unsigned long flags;
+ struct timer_list *p;
+
+#if SLOW_BUT_DEBUGGING_TIMERS
+ if (timer->next || timer->prev) {
+ printk("add_timer() called with non-zero list from %p\n",
+ __builtin_return_address(0));
+ return;
+ }
+#endif
+ p = &timer_head;
+ timer->expires += jiffies;
+ save_flags(flags);
+ cli();
+ do {
+ p = p->next;
+ } while (timer->expires > p->expires);
+ timer->next = p;
+ timer->prev = p->prev;
+ p->prev = timer;
+ timer->prev->next = timer;
+ restore_flags(flags);
+}
+
+int del_timer(struct timer_list * timer)
+{
+ unsigned long flags;
+#if SLOW_BUT_DEBUGGING_TIMERS
+ struct timer_list * p;
+
+ p = &timer_head;
+ save_flags(flags);
+ cli();
+ while ((p = p->next) != &timer_head) {
+ if (p == timer) {
+ timer->next->prev = timer->prev;
+ timer->prev->next = timer->next;
+ timer->next = timer->prev = NULL;
+ restore_flags(flags);
+ timer->expires -= jiffies;
+ return 1;
+ }
+ }
+ if (timer->next || timer->prev)
+ printk("del_timer() called from %p with timer not initialized\n",
+ __builtin_return_address(0));
+ restore_flags(flags);
+ return 0;
+#else
+ save_flags(flags);
+ cli();
+ if (timer->next) {
+ timer->next->prev = timer->prev;
+ timer->prev->next = timer->next;
+ timer->next = timer->prev = NULL;
+ restore_flags(flags);
+ timer->expires -= jiffies;
+ return 1;
+ }
+ restore_flags(flags);
+ return 0;
+#endif
+}
+
+unsigned long timer_active = 0;
+struct timer_struct timer_table[32];
+
+/*
+ * Hmm.. Changed this, as the GNU make sources (load.c) seems to
+ * imply that avenrun[] is the standard name for this kind of thing.
+ * Nothing else seems to be standardized: the fractional size etc
+ * all seem to differ on different machines.
+ */
+unsigned long avenrun[3] = { 0,0,0 };
+
+/*
+ * Nr of active tasks - counted in fixed-point numbers
+ */
+static unsigned long count_active_tasks(void)
+{
+ struct task_struct **p;
+ unsigned long nr = 0;
+
+ for(p = &LAST_TASK; p > &FIRST_TASK; --p)
+ if (*p && ((*p)->state == TASK_RUNNING ||
+ (*p)->state == TASK_UNINTERRUPTIBLE ||
+ (*p)->state == TASK_SWAPPING))
+ nr += FIXED_1;
+ return nr;
+}
+
+static inline void calc_load(void)
+{
+ unsigned long active_tasks; /* fixed-point */
+ static int count = LOAD_FREQ;
+
+ if (count-- > 0)
+ return;
+ count = LOAD_FREQ;
+ active_tasks = count_active_tasks();
+ CALC_LOAD(avenrun[0], EXP_1, active_tasks);
+ CALC_LOAD(avenrun[1], EXP_5, active_tasks);
+ CALC_LOAD(avenrun[2], EXP_15, active_tasks);
+}
+
+/*
+ * this routine handles the overflow of the microsecond field
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ *
+ * These were ported to Linux by Philip Gladstone.
+ */
+static void second_overflow(void)
+{
+ long ltemp;
+
+ /* Bump the maxerror field */
+ time_maxerror = (0x70000000-time_maxerror < time_tolerance) ?
+ 0x70000000 : (time_maxerror + time_tolerance);
+
+ /* Run the PLL */
+ if (time_offset < 0) {
+ ltemp = (-(time_offset+1) >> (SHIFT_KG + time_constant)) + 1;
+ time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ time_offset += (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
+ time_adj = - time_adj;
+ } else if (time_offset > 0) {
+ ltemp = ((time_offset-1) >> (SHIFT_KG + time_constant)) + 1;
+ time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ time_offset -= (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
+ } else {
+ time_adj = 0;
+ }
+
+ time_adj += (time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE))
+ + FINETUNE;
+
+ /* Handle the leap second stuff */
+ switch (time_status) {
+ case TIME_INS:
+ /* ugly divide should be replaced */
+ if (xtime.tv_sec % 86400 == 0) {
+ xtime.tv_sec--; /* !! */
+ time_status = TIME_OOP;
+ printk("Clock: inserting leap second 23:59:60 UTC\n");
+ }
+ break;
+
+ case TIME_DEL:
+ /* ugly divide should be replaced */
+ if (xtime.tv_sec % 86400 == 86399) {
+ xtime.tv_sec++;
+ time_status = TIME_OK;
+ printk("Clock: deleting leap second 23:59:59 UTC\n");
+ }
+ break;
+
+ case TIME_OOP:
+ time_status = TIME_OK;
+ break;
+ }
+}
+
+/*
+ * disregard lost ticks for now.. We don't care enough.
+ */
+static void timer_bh(void * unused)
+{
+ unsigned long mask;
+ struct timer_struct *tp;
+ struct timer_list * timer;
+
+ cli();
+ while ((timer = timer_head.next) != &timer_head && timer->expires < jiffies) {
+ void (*fn)(unsigned long) = timer->function;
+ unsigned long data = timer->data;
+ timer->next->prev = timer->prev;
+ timer->prev->next = timer->next;
+ timer->next = timer->prev = NULL;
+ sti();
+ fn(data);
+ cli();
+ }
+ sti();
+
+ for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
+ if (mask > timer_active)
+ break;
+ if (!(mask & timer_active))
+ continue;
+ if (tp->expires > jiffies)
+ continue;
+ timer_active &= ~mask;
+ tp->fn();
+ sti();
+ }
+}
+
+void tqueue_bh(void * unused)
+{
+ run_task_queue(&tq_timer);
+}
+
+void immediate_bh(void * unused)
+{
+ run_task_queue(&tq_immediate);
+}
+
+/*
+ * The int argument is really a (struct pt_regs *), in case the
+ * interrupt wants to know from where it was called. The timer
+ * irq uses this to decide if it should update the user or system
+ * times.
+ */
+static void do_timer(int irq, struct pt_regs * regs)
+{
+ unsigned long mask;
+ struct timer_struct *tp;
+ /* last time the cmos clock got updated */
+ static long last_rtc_update=0;
+ extern int set_rtc_mmss(unsigned long);
+
+ long ltemp, psecs;
+
+ /* Advance the phase, once it gets to one microsecond, then
+ * advance the tick more.
+ */
+ time_phase += time_adj;
+ if (time_phase < -FINEUSEC) {
+ ltemp = -time_phase >> SHIFT_SCALE;
+ time_phase += ltemp << SHIFT_SCALE;
+ xtime.tv_usec += tick + time_adjust_step - ltemp;
+ }
+ else if (time_phase > FINEUSEC) {
+ ltemp = time_phase >> SHIFT_SCALE;
+ time_phase -= ltemp << SHIFT_SCALE;
+ xtime.tv_usec += tick + time_adjust_step + ltemp;
+ } else
+ xtime.tv_usec += tick + time_adjust_step;
+
+ if (time_adjust)
+ {
+ /* We are doing an adjtime thing.
+ *
+ * Modify the value of the tick for next time.
+ * Note that a positive delta means we want the clock
+ * to run fast. This means that the tick should be bigger
+ *
+ * Limit the amount of the step for *next* tick to be
+ * in the range -tickadj .. +tickadj
+ */
+ if (time_adjust > tickadj)
+ time_adjust_step = tickadj;
+ else if (time_adjust < -tickadj)
+ time_adjust_step = -tickadj;
+ else
+ time_adjust_step = time_adjust;
+
+ /* Reduce by this step the amount of time left */
+ time_adjust -= time_adjust_step;
+ }
+ else
+ time_adjust_step = 0;
+
+ if (xtime.tv_usec >= 1000000) {
+ xtime.tv_usec -= 1000000;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+
+ /* If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if (time_status != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+ jiffies++;
+ calc_load();
+ if (user_mode(regs)) {
+ current->utime++;
+ if (current != task[0]) {
+ if (current->priority < 15)
+ kstat.cpu_nice++;
+ else
+ kstat.cpu_user++;
+ }
+ /* Update ITIMER_VIRT for current task if not in a system call */
+ if (current->it_virt_value && !(--current->it_virt_value)) {
+ current->it_virt_value = current->it_virt_incr;
+ send_sig(SIGVTALRM,current,1);
+ }
+ } else {
+ current->stime++;
+ if(current != task[0])
+ kstat.cpu_system++;
+#ifdef CONFIG_PROFILE
+ if (prof_buffer && current != task[0]) {
+ extern int _stext;
+ unsigned long eip = regs->eip - (unsigned long) &_stext;
+ eip >>= CONFIG_PROFILE_SHIFT;
+ if (eip < prof_len)
+ prof_buffer[eip]++;
+ }
+#endif
+ }
+ /*
+ * check the cpu time limit on the process.
+ */
+ if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
+ (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
+ send_sig(SIGKILL, current, 1);
+ if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
+ (((current->stime + current->utime) % HZ) == 0)) {
+ psecs = (current->stime + current->utime) / HZ;
+ /* send when equal */
+ if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
+ send_sig(SIGXCPU, current, 1);
+ /* and every five seconds thereafter. */
+ else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
+ ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
+ send_sig(SIGXCPU, current, 1);
+ }
+
+ if (current != task[0] && 0 > --current->counter) {
+ current->counter = 0;
+ need_resched = 1;
+ }
+ /* Update ITIMER_PROF for the current task */
+ if (current->it_prof_value && !(--current->it_prof_value)) {
+ current->it_prof_value = current->it_prof_incr;
+ send_sig(SIGPROF,current,1);
+ }
+ for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
+ if (mask > timer_active)
+ break;
+ if (!(mask & timer_active))
+ continue;
+ if (tp->expires > jiffies)
+ continue;
+ mark_bh(TIMER_BH);
+ }
+ cli();
+ itimer_ticks++;
+ if (itimer_ticks > itimer_next)
+ need_resched = 1;
+ if (timer_head.next->expires < jiffies)
+ mark_bh(TIMER_BH);
+ if (tq_timer != &tq_last)
+ mark_bh(TQUEUE_BH);
+ sti();
+}
+
+asmlinkage int sys_alarm(long seconds)
+{
+ struct itimerval it_new, it_old;
+
+ it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+ it_new.it_value.tv_sec = seconds;
+ it_new.it_value.tv_usec = 0;
+ _setitimer(ITIMER_REAL, &it_new, &it_old);
+ return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
+}
+
+asmlinkage int sys_getpid(void)
+{
+ return current->pid;
+}
+
+asmlinkage int sys_getppid(void)
+{
+ return current->p_opptr->pid;
+}
+
+asmlinkage int sys_getuid(void)
+{
+ return current->uid;
+}
+
+asmlinkage int sys_geteuid(void)
+{
+ return current->euid;
+}
+
+asmlinkage int sys_getgid(void)
+{
+ return current->gid;
+}
+
+asmlinkage int sys_getegid(void)
+{
+ return current->egid;
+}
+
+asmlinkage int sys_nice(long increment)
+{
+ int newprio;
+
+ if (increment < 0 && !suser())
+ return -EPERM;
+ newprio = current->priority - increment;
+ if (newprio < 1)
+ newprio = 1;
+ if (newprio > 35)
+ newprio = 35;
+ current->priority = newprio;
+ return 0;
+}
+
+static void show_task(int nr,struct task_struct * p)
+{
+ unsigned long free;
+ static char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
+
+ printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
+ if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *))
+ printk(stat_nam[p->state]);
+ else
+ printk(" ");
+#ifdef __i386__
+ if (p == current)
+ printk(" current ");
+ else
+ printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]);
+#elif defined (__mips__)
+ if (p == current)
+ printk(" current ");
+ else
+ printk(" ");
+#endif
+ for (free = 1; free < 1024 ; free++) {
+ if (((unsigned long *)p->kernel_stack_page)[free])
+ break;
+ }
+ printk("%5lu %5d %6d ", free << 2, p->pid, p->p_pptr->pid);
+ if (p->p_cptr)
+ printk("%5d ", p->p_cptr->pid);
+ else
+ printk(" ");
+ if (p->p_ysptr)
+ printk("%7d", p->p_ysptr->pid);
+ else
+ printk(" ");
+ if (p->p_osptr)
+ printk(" %5d\n", p->p_osptr->pid);
+ else
+ printk("\n");
+}
+
+void show_state(void)
+{
+ int i;
+
+ printk(" free sibling\n");
+ printk(" task PC stack pid father child younger older\n");
+ for (i=0 ; i<NR_TASKS ; i++)
+ if (task[i])
+ show_task(i,task[i]);
+}
+
+void sched_init(void)
+{
+ bh_base[TIMER_BH].routine = timer_bh;
+ bh_base[TQUEUE_BH].routine = tqueue_bh;
+ bh_base[IMMEDIATE_BH].routine = immediate_bh;
+ if (request_irq(TIMER_IRQ, do_timer, 0, "timer") != 0)
+ panic("Could not allocate timer IRQ!");
+ enable_bh(TIMER_BH);
+ enable_bh(TQUEUE_BH);
+ enable_bh(IMMEDIATE_BH);
+}
diff --git a/kernel/signal.c b/kernel/signal.c
new file mode 100644
index 000000000..f21d7a2c9
--- /dev/null
+++ b/kernel/signal.c
@@ -0,0 +1,174 @@
+/*
+ * linux/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
+{
+ sigset_t new_set, old_set = current->blocked;
+ int error;
+
+ if (set) {
+ error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
+ if (error)
+ return error;
+ new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
+ switch (how) {
+ case SIG_BLOCK:
+ current->blocked |= new_set;
+ break;
+ case SIG_UNBLOCK:
+ current->blocked &= ~new_set;
+ break;
+ case SIG_SETMASK:
+ current->blocked = new_set;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ if (oset) {
+ error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
+ if (error)
+ return error;
+ put_fs_long(old_set, (unsigned long *) oset);
+ }
+ return 0;
+}
+
+asmlinkage int sys_sgetmask(void)
+{
+ return current->blocked;
+}
+
+asmlinkage int sys_ssetmask(int newmask)
+{
+ int old=current->blocked;
+
+ current->blocked = newmask & _BLOCKABLE;
+ return old;
+}
+
+asmlinkage int sys_sigpending(sigset_t *set)
+{
+ int error;
+ /* fill in "set" with signals pending but blocked. */
+ error = verify_area(VERIFY_WRITE, set, 4);
+ if (!error)
+ put_fs_long(current->blocked & current->signal, (unsigned long *)set);
+ return error;
+}
+
+/*
+ * POSIX 3.3.1.3:
+ * "Setting a signal action to SIG_IGN for a signal that is pending
+ * shall cause the pending signal to be discarded, whether or not
+ * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
+ *
+ * "Setting a signal action to SIG_DFL for a signal that is pending
+ * and whose default action is to ignore the signal (for example,
+ * SIGCHLD), shall cause the pending signal to be discarded, whether
+ * or not it is blocked"
+ *
+ * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
+ * isn't actually ignored, but does automatic child reaping, while
+ * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
+ */
+static void check_pending(int signum)
+{
+ struct sigaction *p;
+
+ p = signum - 1 + current->sigaction;
+ if (p->sa_handler == SIG_IGN) {
+ if (signum == SIGCHLD)
+ return;
+ current->signal &= ~_S(signum);
+ return;
+ }
+ if (p->sa_handler == SIG_DFL) {
+ if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
+ return;
+ current->signal &= ~_S(signum);
+ return;
+ }
+}
+
+asmlinkage unsigned long sys_signal(int signum, void (*handler)(int))
+{
+ int err;
+ struct sigaction tmp;
+
+ if (signum<1 || signum>32)
+ return -EINVAL;
+ if (signum==SIGKILL || signum==SIGSTOP)
+ return -EINVAL;
+ if (handler != SIG_DFL && handler != SIG_IGN) {
+ err = verify_area(VERIFY_READ, handler, 1);
+ if (err)
+ return err;
+ }
+ tmp.sa_handler = handler;
+ tmp.sa_mask = 0;
+ tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
+ tmp.sa_restorer = NULL;
+ handler = current->sigaction[signum-1].sa_handler;
+ current->sigaction[signum-1] = tmp;
+ check_pending(signum);
+ return (unsigned long) handler;
+}
+
+asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
+ struct sigaction * oldaction)
+{
+ struct sigaction new_sa, *p;
+
+ if (signum<1 || signum>32)
+ return -EINVAL;
+ if (signum==SIGKILL || signum==SIGSTOP)
+ return -EINVAL;
+ p = signum - 1 + current->sigaction;
+ if (action) {
+ int err = verify_area(VERIFY_READ, action, sizeof(*action));
+ if (err)
+ return err;
+ memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
+ if (new_sa.sa_flags & SA_NOMASK)
+ new_sa.sa_mask = 0;
+ else {
+ new_sa.sa_mask |= _S(signum);
+ new_sa.sa_mask &= _BLOCKABLE;
+ }
+ if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
+ err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+ if (err)
+ return err;
+ }
+ }
+ if (oldaction) {
+ int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
+ if (err)
+ return err;
+ memcpy_tofs(oldaction, p, sizeof(struct sigaction));
+ }
+ if (action) {
+ *p = new_sa;
+ check_pending(signum);
+ }
+ return 0;
+}
diff --git a/kernel/softirq.c b/kernel/softirq.c
new file mode 100644
index 000000000..7d919272b
--- /dev/null
+++ b/kernel/softirq.c
@@ -0,0 +1,55 @@
+/*
+ * linux/kernel/softirq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ *
+ * do_bottom_half() runs at normal kernel priority: all interrupts
+ * enabled. do_bottom_half() is atomic with respect to itself: a
+ * bottom_half handler need not be re-entrant.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#define INCLUDE_INLINE_FUNCS
+#include <linux/tqueue.h>
+
+unsigned long intr_count = 0;
+
+unsigned long bh_active = 0;
+unsigned long bh_mask = 0;
+struct bh_struct bh_base[32];
+
+
+asmlinkage void do_bottom_half(void)
+{
+ unsigned long active;
+ unsigned long mask, left;
+ struct bh_struct *bh;
+
+ bh = bh_base;
+ active = bh_active & bh_mask;
+ for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
+ if (mask & active) {
+ void (*fn)(void *);
+ bh_active &= ~mask;
+ fn = bh->routine;
+ if (!fn)
+ goto bad_bh;
+ fn(bh->data);
+ }
+ }
+ return;
+bad_bh:
+ printk ("irq.c:bad bottom half entry %08lx\n", mask);
+}
diff --git a/kernel/sys.c b/kernel/sys.c
index 706e3d66e..171d2411c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,7 +4,6 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -17,6 +16,7 @@
#include <linux/ptrace.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/io.h>
@@ -32,38 +32,7 @@ extern void adjust_clock(void);
asmlinkage int sys_ni_syscall(void)
{
- return -EINVAL;
-}
-
-asmlinkage int sys_idle(void)
-{
- int i;
-
- if (current->pid != 0)
- return -EPERM;
-
-#ifdef __i386__
- /* Map out the low memory: it's no longer needed */
- for (i = 0 ; i < 768 ; i++)
- swapper_pg_dir[i] = 0;
-#endif
-
- /* endless idle loop with no priority at all */
- current->counter = -100;
- for (;;) {
-#if defined (__i386__)
- if (hlt_works_ok && !need_resched)
- __asm__("hlt");
-#elif defined (__mips__)
- /*
- * R4[26]00 have wait, the R4000 doesn't.
- * Dunno about the R4400...
- */
- if (!need_resched)
- __asm__("wait");
-#endif
- schedule();
- }
+ return -ENOSYS;
}
static int proc_sel(struct task_struct *p, int which, int who)
@@ -163,6 +132,7 @@ asmlinkage int sys_prof(void)
}
extern void hard_reset_now(void);
+extern asmlinkage sys_kill(int, int);
/*
* Reboot system call: for obvious reasons only root may call it,
@@ -184,7 +154,11 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
C_A_D = 1;
else if (!flag)
C_A_D = 0;
- else
+ else if (flag == 0xCDEF0123) {
+ printk(KERN_EMERG "System halted\n");
+ sys_kill(-1, SIGKILL);
+ do_exit(0);
+ } else
return -EINVAL;
return (0);
}
@@ -402,12 +376,11 @@ asmlinkage int sys_times(struct tms * tbuf)
return jiffies;
}
-asmlinkage int sys_brk(unsigned long brk)
+asmlinkage unsigned long sys_brk(unsigned long brk)
{
int freepages;
unsigned long rlim;
unsigned long newbrk, oldbrk;
- struct vm_area_struct * vma;
if (brk < current->mm->end_code)
return current->mm->brk;
@@ -430,18 +403,13 @@ asmlinkage int sys_brk(unsigned long brk)
rlim = current->rlim[RLIMIT_DATA].rlim_cur;
if (rlim >= RLIM_INFINITY)
rlim = ~0;
- if (brk - current->mm->end_code > rlim ||
- brk >= current->mm->start_stack - 16384)
+ if (brk - current->mm->end_code > rlim)
return current->mm->brk;
/*
* Check against existing mmap mappings.
*/
- for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
- if (newbrk <= vma->vm_start)
- break;
- if (oldbrk < vma->vm_end)
- return current->mm->brk;
- }
+ if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
+ return current->mm->brk;
/*
* stupid algorithm to decide if we have enough memory: while
* simple, it hopefully works in most obvious cases.. Easy to
@@ -450,7 +418,14 @@ asmlinkage int sys_brk(unsigned long brk)
freepages = buffermem >> 12;
freepages += nr_free_pages;
freepages += nr_swap_pages;
+#if 0
+ /*
+ * This assumes a PCish memory architecture...
+ */
freepages -= (high_memory - 0x100000) >> 16;
+#else
+ freepages -= (high_memory - KSEG0) >> 16;
+#endif
freepages -= (newbrk-oldbrk) >> 12;
if (freepages < 0)
return current->mm->brk;
@@ -548,6 +523,7 @@ asmlinkage int sys_setsid(void)
current->leader = 1;
current->session = current->pgrp = current->pid;
current->tty = NULL;
+ current->tty_old_pgrp = 0;
return current->pgrp;
}
@@ -557,18 +533,20 @@ asmlinkage int sys_setsid(void)
asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
{
int i;
+ int * groups;
if (gidsetsize) {
i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize);
if (i)
return i;
}
- for (i = 0 ; (i < NGROUPS) && (current->groups[i] != NOGROUP) ; i++) {
+ groups = current->groups;
+ for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) {
if (!gidsetsize)
continue;
if (i >= gidsetsize)
break;
- put_fs_word(current->groups[i], (short *) grouplist);
+ put_user(*groups, grouplist);
grouplist++;
}
return(i);
@@ -660,22 +638,35 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
return 0;
}
-/*
- * Only sethostname; gethostname can be implemented by calling uname()
- */
asmlinkage int sys_sethostname(char *name, int len)
{
- int i;
-
+ int error;
+
if (!suser())
return -EPERM;
- if (len > __NEW_UTS_LEN)
+ if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
- for (i=0; i < len; i++) {
- if ((system_utsname.nodename[i] = get_fs_byte(name+i)) == 0)
- return 0;
- }
- system_utsname.nodename[i] = 0;
+ error = verify_area(VERIFY_READ, name, len);
+ if (error)
+ return error;
+ memcpy_fromfs(system_utsname.nodename, name, len);
+ system_utsname.nodename[len] = 0;
+ return 0;
+}
+
+asmlinkage int sys_gethostname(char *name, int len)
+{
+ int i;
+
+ if (len < 0)
+ return -EINVAL;
+ i = verify_area(VERIFY_WRITE, name, len);
+ if (i)
+ return i;
+ i = 1+strlen(system_utsname.nodename);
+ if (i > len)
+ i = len;
+ memcpy_tofs(name, system_utsname.nodename, i);
return 0;
}
@@ -708,10 +699,7 @@ asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
error = verify_area(VERIFY_WRITE,rlim,sizeof *rlim);
if (error)
return error;
- put_fs_long(current->rlim[resource].rlim_cur,
- (unsigned long *) rlim);
- put_fs_long(current->rlim[resource].rlim_max,
- ((unsigned long *) rlim)+1);
+ memcpy_tofs(rlim, current->rlim + resource, sizeof(*rlim));
return 0;
}
@@ -731,6 +719,10 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
!suser())
return -EPERM;
+ if (resource == RLIMIT_NOFILE) {
+ if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
+ return -EPERM;
+ }
*old_rlim = new_rlim;
return 0;
}
diff --git a/kernel/time.c b/kernel/time.c
index 1a25d43ef..0424b2eaa 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -10,39 +10,48 @@
/*
* Modification history kernel/time.c
*
- * 02 Sep 93 Philip Gladstone
+ * 1993-09-02 Philip Gladstone
* Created file with time related functions from sched.c and adjtimex()
- * 08 Oct 93 Torsten Duwe
+ * 1993-10-08 Torsten Duwe
* adjtime interface update and CMOS clock write code
- * 02 Jul 94 Alan Modra
+ * 1994-07-02 Alan Modra
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ *
+ * to do: adjtimex() has to be updated to recent (1994-12-13) revision
+ * of David Mill's kernel clock model. For more information, check
+ * <ftp://louie.udel.edu/pub/ntp/kernel.tar.Z>.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
+#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/mc146818rtc.h>
-#define RTC_ALWAYS_BCD 1
-
#include <linux/timex.h>
-/* converts date to days since 1/1/1970
- * assumes year,mon,day in normal date format
- * ie. 1/1/1970 => year=1970, mon=1, day=1
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
- * For the Julian calendar (which was used in Russia before 1917,
+ * [For the Julian calendar (which was used in Russia before 1917,
* Britain & colonies before 1752, anywhere else before 1582,
* and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.
+ * -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
*/
static inline unsigned long mktime(unsigned int year, unsigned int mon,
unsigned int day, unsigned int hour,
@@ -65,16 +74,16 @@ void time_init(void)
unsigned int year, mon, day, hour, min, sec;
int i;
- /* checking for Update-In-Progress could be done more elegantly
- * (using the "update finished"-interrupt for example), but that
- * would require excessive testing. promise I'll do that when I find
- * the time. - Torsten
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
- for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms*/
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
@@ -98,7 +107,14 @@ void time_init(void)
year += 100;
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
+printk("Year : %d\n", year);
+printk("Mon : %d\n", mon);
+printk("Day : %d\n", day);
+printk("Hour : %d\n", hour);
+printk("Min : %d\n", min);
+printk("Sec : %d\n", sec);
}
+
/*
* The timezone where the local system is located. Used as a default by some
* programs who obtain this value by using gettimeofday.
@@ -148,25 +164,25 @@ asmlinkage int sys_stime(unsigned long * tptr)
* counter rather than 11932! This has an adverse impact on
* do_gettimeoffset() -- it stops working! What is also not
* good is that the interval that our timer function gets called
- * is no longer 10.0002 msecs, but 9.9767 msec. To get around this
+ * is no longer 10.0002 ms, but 9.9767 ms. To get around this
* would require using a different timing source. Maybe someone
* could use the RTC - I know that this can interrupt at frequencies
* ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
* it so that at startup, the timer code in sched.c would select
* using either the RTC or the 8253 timer. The decision would be
* based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024Hz,
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
* and then do some jiggery to have a version of do_timer that
- * advanced the clock by 1/1024 sec. Every time that reached over 1/100
+ * advanced the clock by 1/1024 s. Every time that reached over 1/100
* of a second, then do all the old code. If the time was kept correct
* then do_gettimeoffset could just return 0 - there is no low order
* divider that can be accessed.
*
* Ideally, you would be able to use the RTC for the speaker driver,
* but it appears that the speaker driver really needs interrupt more
- * often than every 120us or so.
+ * often than every 120 us or so.
*
- * Anyway, this needs more thought.... pjsg (28 Aug 93)
+ * Anyway, this needs more thought.... pjsg (1993-08-28)
*
* If you are really that interested, you should be reading
* comp.protocols.time.ntp!
@@ -198,22 +214,21 @@ static inline unsigned long do_gettimeoffset(void)
/*
* This version of gettimeofday has near microsecond resolution.
*/
-static inline void do_gettimeofday(struct timeval *tv)
+void do_gettimeofday(struct timeval *tv)
{
-#if defined (__i386__) || defined (__mips__)
+ unsigned long flags;
+
+ save_flags(flags);
cli();
*tv = xtime;
+#if defined (__i386__) || defined (__mips__)
tv->tv_usec += do_gettimeoffset();
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
- sti();
-#else /* not __i386__ */
- cli();
- *tv = xtime;
- sti();
-#endif /* not __i386__ */
+#endif /* !defined (__i386__) && !defined (__mips__) */
+ restore_flags(flags);
}
asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -226,21 +241,19 @@ asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
if (error)
return error;
do_gettimeofday(&ktv);
- put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
- put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
+ memcpy_tofs(tv, &ktv, sizeof(ktv));
}
if (tz) {
error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
if (error)
return error;
- put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
- put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
+ memcpy_tofs(tz, &sys_tz, sizeof(sys_tz));
}
return 0;
}
/*
- * Adjust the time obtained from the CMOS to be GMT time instead of
+ * Adjust the time obtained from the CMOS to be UTC time instead of
* local time.
*
* This is ugly, but preferable to the alternatives. Otherwise we
@@ -249,11 +262,11 @@ asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
* hard to make the program warp the clock precisely n hours) or
* compile in the timezone information into the kernel. Bad, bad....
*
- * XXX Currently does not adjust for daylight savings time. May not
- * need to do anything, depending on how smart (dumb?) the BIOS
- * is. Blast it all.... the best thing to do not depend on the CMOS
- * clock at all, but get the time via NTP or timed if you're on a
- * network.... - TYT, 1/1/92
+ * - TYT, 1992-01-01
+ *
+ * The best thing to do is to keep the CMOS clock in universal time (UTC)
+ * as real UNIX machines always do it. This avoids all headaches about
+ * daylight saving times and warping kernel clocks.
*/
inline static void warp_clock(void)
{
@@ -263,12 +276,13 @@ inline static void warp_clock(void)
}
/*
- * The first time we set the timezone, we will warp the clock so that
- * it is ticking GMT time instead of local time. Presumably,
- * if someone is setting the timezone then we are running in an
- * environment where the programs understand about timezones.
- * This should be done at boot time in the /etc/rc script, as
- * soon as possible, so that the clock can be set right. Otherwise,
+ * In case for some reason the CMOS clock has not already been running
+ * in UTC, but in some local time: The first time we set the timezone,
+ * we will warp the clock so that it is ticking UTC time instead of
+ * local time. Presumably, if someone is setting the timezone then we
+ * are running in an environment where the programs understand about
+ * timezones. This should be done at boot time in the /etc/rc script,
+ * as soon as possible, so that the clock can be set right. Otherwise,
* various programs will get confused when the clock gets warped.
*/
asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
@@ -441,6 +455,13 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
return time_status;
}
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ */
int set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
@@ -481,7 +502,15 @@ int set_rtc_mmss(unsigned long nowtime)
else
retval = -1;
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
return retval;
}
diff --git a/kernel/tqueue.c b/kernel/tqueue.c
deleted file mode 100644
index 440709611..000000000
--- a/kernel/tqueue.c
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * tqueue.c --- task queue handling for Linux.
- *
- * This routine merely draws in the static portion of the task queue
- * inline functions. Look in tqueue.h for the relevant functions.
- */
-
-#define INCLUDE_INLINE_FUNCS
-
-#include <linux/tqueue.h>
diff --git a/kernel/vsprintf.c b/kernel/vsprintf.c
deleted file mode 100644
index b85f78420..000000000
--- a/kernel/vsprintf.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * linux/kernel/vsprintf.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
-/*
- * Wirzenius wrote this portably, Torvalds fucked it up :-)
- */
-
-#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
- unsigned long result = 0,value;
-
- if (!base) {
- base = 10;
- if (*cp == '0') {
- base = 8;
- cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
- cp++;
- base = 16;
- }
- }
- }
- while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
- ? toupper(*cp) : *cp)-'A'+10) < base) {
- result = result*base + value;
- cp++;
- }
- if (endp)
- *endp = (char *)cp;
- return result;
-}
-
-/* we use this so that we can do without the ctype library */
-#define is_digit(c) ((c) >= '0' && (c) <= '9')
-
-static int skip_atoi(const char **s)
-{
- int i=0;
-
- while (is_digit(**s))
- i = i*10 + *((*s)++) - '0';
- return i;
-}
-
-#define ZEROPAD 1 /* pad with zero */
-#define SIGN 2 /* unsigned/signed long */
-#define PLUS 4 /* show plus */
-#define SPACE 8 /* space if plus */
-#define LEFT 16 /* left justified */
-#define SPECIAL 32 /* 0x */
-#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
-
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
-static char * number(char * str, long num, int base, int size, int precision
- ,int type)
-{
- char c,sign,tmp[36];
- const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
- int i;
-
- if (type & LARGE)
- digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- if (type & LEFT)
- type &= ~ZEROPAD;
- if (base < 2 || base > 36)
- return 0;
- c = (type & ZEROPAD) ? '0' : ' ';
- sign = 0;
- if (type & SIGN) {
- if (num < 0) {
- sign = '-';
- num = -num;
- size--;
- } else if (type & PLUS) {
- sign = '+';
- size--;
- } else if (type & SPACE) {
- sign = ' ';
- size--;
- }
- }
- if (type & SPECIAL) {
- if (base == 16)
- size -= 2;
- else if (base == 8)
- size--;
- }
- i = 0;
- if (num == 0)
- tmp[i++]='0';
- else while (num != 0)
- tmp[i++] = digits[do_div(num,base)];
- if (i > precision)
- precision = i;
- size -= precision;
- if (!(type&(ZEROPAD+LEFT)))
- while(size-->0)
- *str++ = ' ';
- if (sign)
- *str++ = sign;
- if (type & SPECIAL)
- if (base==8)
- *str++ = '0';
- else if (base==16) {
- *str++ = '0';
- *str++ = digits[33];
- }
- if (!(type & LEFT))
- while (size-- > 0)
- *str++ = c;
- while (i < precision--)
- *str++ = '0';
- while (i-- > 0)
- *str++ = tmp[i];
- while (size-- > 0)
- *str++ = ' ';
- return str;
-}
-
-int vsprintf(char *buf, const char *fmt, va_list args)
-{
- int len;
- unsigned long num;
- int i, base;
- char * str;
- char *s;
-
- int flags; /* flags to number() */
-
- int field_width; /* width of output field */
- int precision; /* min. # of digits for integers; max
- number of chars for from string */
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
-
- for (str=buf ; *fmt ; ++fmt) {
- if (*fmt != '%') {
- *str++ = *fmt;
- continue;
- }
-
- /* process flags */
- flags = 0;
- repeat:
- ++fmt; /* this also skips first '%' */
- switch (*fmt) {
- case '-': flags |= LEFT; goto repeat;
- case '+': flags |= PLUS; goto repeat;
- case ' ': flags |= SPACE; goto repeat;
- case '#': flags |= SPECIAL; goto repeat;
- case '0': flags |= ZEROPAD; goto repeat;
- }
-
- /* get field width */
- field_width = -1;
- if (is_digit(*fmt))
- field_width = skip_atoi(&fmt);
- else if (*fmt == '*') {
- ++fmt;
- /* it's the next argument */
- field_width = va_arg(args, int);
- if (field_width < 0) {
- field_width = -field_width;
- flags |= LEFT;
- }
- }
-
- /* get the precision */
- precision = -1;
- if (*fmt == '.') {
- ++fmt;
- if (is_digit(*fmt))
- precision = skip_atoi(&fmt);
- else if (*fmt == '*') {
- ++fmt;
- /* it's the next argument */
- precision = va_arg(args, int);
- }
- if (precision < 0)
- precision = 0;
- }
-
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
- qualifier = *fmt;
- ++fmt;
- }
-
- /* default base */
- base = 10;
-
- switch (*fmt) {
- case 'c':
- if (!(flags & LEFT))
- while (--field_width > 0)
- *str++ = ' ';
- *str++ = (unsigned char) va_arg(args, int);
- while (--field_width > 0)
- *str++ = ' ';
- continue;
-
- case 's':
- s = va_arg(args, char *);
- if (!s)
- s = "<NULL>";
- len = strlen(s);
- if (precision < 0)
- precision = len;
- else if (len > precision)
- len = precision;
-
- if (!(flags & LEFT))
- while (len < field_width--)
- *str++ = ' ';
- for (i = 0; i < len; ++i)
- *str++ = *s++;
- while (len < field_width--)
- *str++ = ' ';
- continue;
-
- case 'p':
- if (field_width == -1) {
- field_width = 2*sizeof(void *);
- flags |= ZEROPAD;
- }
- str = number(str,
- (unsigned long) va_arg(args, void *), 16,
- field_width, precision, flags);
- continue;
-
-
- case 'n':
- if (qualifier == 'l') {
- long * ip = va_arg(args, long *);
- *ip = (str - buf);
- } else {
- int * ip = va_arg(args, int *);
- *ip = (str - buf);
- }
- continue;
-
- /* integer number formats - set up the flags and "break" */
- case 'o':
- base = 8;
- break;
-
- case 'X':
- flags |= LARGE;
- case 'x':
- base = 16;
- break;
-
- case 'd':
- case 'i':
- flags |= SIGN;
- case 'u':
- break;
-
- default:
- if (*fmt != '%')
- *str++ = '%';
- if (*fmt)
- *str++ = *fmt;
- else
- --fmt;
- continue;
- }
- if (qualifier == 'l')
- num = va_arg(args, unsigned long);
- else if (qualifier == 'h')
- if (flags & SIGN)
- num = va_arg(args, short);
- else
- num = va_arg(args, unsigned short);
- else if (flags & SIGN)
- num = va_arg(args, int);
- else
- num = va_arg(args, unsigned int);
- str = number(str, num, base, field_width, precision, flags);
- }
- *str = '\0';
- return str-buf;
-}
-
-int sprintf(char * buf, const char *fmt, ...)
-{
- va_list args;
- int i;
-
- va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
- va_end(args);
- return i;
-}
-