--- linux-2.5.69/include/linux/umlsim.h.orig	Tue May 27 02:22:06 2003
+++ linux-2.5.69/include/linux/umlsim.h	Wed May 28 10:23:01 2003
@@ -0,0 +1,28 @@
+/*
+ * linux/umlsim.h - UML simulator support
+ *
+ * Written 2002,2003 by Werner Almesberger
+ * Copyright 2002 Werner Almesberger
+ * Copyright 2003 California Institute of Technology
+ */
+
+#ifndef _LINUX_UMLSIM_H
+#define _LINUX_UMLSIM_H
+
+#include <linux/config.h>
+
+#if defined(CONFIG_UMLSIM) || defined(UMLSIM_USER)
+extern int umlsim_real_time;
+#else
+#define umlsim_real_time 1
+#endif
+
+extern int umlsim_fds[2];
+
+/* from kernel/timer.c */
+extern unsigned long next_timer_jiffies(void);
+
+/* umlsim_user.c */
+void umlsim_timer_interrupt(void);
+
+#endif /* _LINUX_UMLSIM_H */
--- linux-2.5.69/init/main.c.orig	Sun May  4 20:53:03 2003
+++ linux-2.5.69/init/main.c	Tue May 27 02:22:06 2003
@@ -37,6 +37,7 @@
 #include <linux/rcupdate.h>
 #include <linux/moduleparam.h>
 #include <linux/writeback.h>
+#include <linux/umlsim.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -177,6 +178,8 @@
 	unsigned long ticks, loopbit;
 	int lps_precision = LPS_PREC;
 
+	if (!umlsim_real_time) return;
+
 	loops_per_jiffy = (1<<12);
 
 	printk("Calibrating delay loop... ");
--- linux-2.5.69/kernel/timer.c.orig	Sun May  4 20:53:37 2003
+++ linux-2.5.69/kernel/timer.c	Tue May 27 02:22:06 2003
@@ -19,6 +19,7 @@
  *              Designed by David S. Miller, Alexey Kuznetsov and Ingo Molnar
  */
 
+#include <linux/config.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
@@ -1221,3 +1222,71 @@
 	register_cpu_notifier(&timers_nb);
 	open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
 }
+
+
+#ifdef CONFIG_UMLSIM
+
+/*
+ * Find out when the next timer will expire (for umlsim)
+ */
+
+
+static const struct list_head *next_timer_head(const struct tvec_t_base_s *base)
+{
+	const struct list_head *head;
+	int i;
+
+	for (i = 0; i < TVR_SIZE; i++) {
+		head = base->tv1.vec+((base->timer_jiffies+i) & TVR_MASK);
+		if (head->next != head)
+			return head;
+	}
+	for (i = 0; i < TVN_SIZE; i++) {
+		head = base->tv2.vec+(((INDEX(0))+i) & TVN_MASK);
+		if (head->next != head)
+			return head;
+	}
+	for (i = 0; i < TVN_SIZE; i++) {
+		head = base->tv3.vec+(((INDEX(1))+i) & TVN_MASK);
+		if (head->next != head)
+			return head;
+	}
+	for (i = 0; i < TVN_SIZE; i++) {
+		head = base->tv4.vec+(((INDEX(2))+i) & TVN_MASK);
+		if (head->next != head)
+			return head;
+	}
+	for (i = 0; i < TVN_SIZE; i++) {
+		head = base->tv5.vec+(((INDEX(3))+i) & TVN_MASK);
+		if (head->next != head)
+			return head;
+	}
+	return NULL;
+}
+
+
+unsigned long next_timer_jiffies(void)
+{
+	struct tvec_t_base_s *base = &per_cpu(tvec_bases,smp_processor_id());
+	const struct list_head *head;
+	unsigned long flags;
+	unsigned long res = ~0UL;
+
+	spin_lock_irqsave(&base->lock, flags);
+	head = next_timer_head(base);
+	if (head) {
+		struct list_head *curr;
+
+		for (curr = head->next; curr != head; curr = curr->next) {
+			unsigned long expires =
+			    list_entry(curr,struct timer_list,entry)->expires;
+
+			if (expires < res)
+				res = expires;
+		}
+	}
+	spin_unlock_irqrestore(&base->lock, flags);
+	return res;
+}
+
+#endif /* CONFIG_UMLSIM */
--- linux-2.5.69/arch/um/Makefile.orig	Tue May 27 02:22:05 2003
+++ linux-2.5.69/arch/um/Makefile	Wed May 28 03:25:37 2003
@@ -32,7 +32,8 @@
 ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
 	$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
 
-GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
+GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h \
+	       $(ARCH_DIR)/include/umlsim.h
 
 .PHONY: sys_prepare
 sys_prepare:
@@ -63,6 +64,13 @@
 
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
+ifeq ($(CONFIG_UMLSIM), y)
+  UMLSIM_SYMBOLS=setitimer do_timer do_gettimeofday gettimeofday
+  LINK_WRAPS += $(UMLSIM_SYMBOLS:%=-Wl,--wrap,%) \
+    $(foreach s,$(UMLSIM_SYMBOLS),"-Wl,--defsym,__towards_$(s)=__real_$(s)")
+  LDFLAGS += $(UMLSIM_SYMBOLS:%=--wrap %)
+endif
+
 SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
 
 ifeq ($(CONFIG_MODE_SKAS), y)
@@ -189,4 +197,7 @@
 $(ARCH_DIR)/util: FORCE
 	$(MAKE) -f scripts/Makefile.build obj=$@
 
+$(ARCH_DIR)/include/umlsim.h:
+	ln -s $(TOPDIR)/include/linux/umlsim.h $(ARCH_DIR)/include
+
 export SUBARCH USER_CFLAGS OS 
--- linux-2.5.69/arch/um/kernel/Makefile.orig	Tue May 27 02:22:06 2003
+++ linux-2.5.69/arch/um/kernel/Makefile	Tue May 27 02:22:06 2003
@@ -15,6 +15,7 @@
 obj-$(CONFIG_GPROF)	+= gprof_syms.o
 obj-$(CONFIG_GCOV)	+= gmon_syms.o
 obj-$(CONFIG_TTY_LOG)	+= tty_log.o
+obj-$(CONFIG_UMLSIM)	+= umlsim_kern.o umlsim_user.o umlsim_inline.o
 
 obj-$(CONFIG_MODE_TT) += tt/
 obj-$(CONFIG_MODE_SKAS) += skas/
@@ -36,6 +37,8 @@
 
 CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
 
+CFLAGS_umlsim_inline.o := -fkeep-inline-functions -Wno-unused-function
+
 $(USER_OBJS) : %.o: %.c
 	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
 
--- linux-2.5.69/arch/um/kernel/umlsim_kern.c.orig	Tue May 27 02:22:06 2003
+++ linux-2.5.69/arch/um/kernel/umlsim_kern.c	Fri May 30 21:38:24 2003
@@ -0,0 +1,364 @@
+/*
+ * umlsim_kern.c - Kernel side of UML simulator support
+ * 
+ * Written 2002,2003 by Werner Almesberger
+ * Copyright 2002 Werner Almesberger
+ * Copyright 2003 California Institute of Technology
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/umlsim.h>
+#include <linux/markers.h>
+#include "init.h"
+
+
+#if 0
+#define __TRACE(s) write(2,s,sizeof(s)-1)
+#define TRACE(s) __TRACE(s "\r\n")
+#else
+#define TRACE(s)
+#endif
+
+
+int umlsim_real_time = 1;		/* clear when using virtual time */
+
+int umlsim_fds[2] = { -1, -1 };
+
+struct timespec umlsim_now;		/* current virtual time */
+
+static struct timespec last_tick;	/* virtual time of last tick */
+static struct timespec next_sync;	/* time at umlsim controller */
+static struct timespec jiffie_ts;	/* timespec increment per jiffie */
+
+static int use_umlsim_idle = 0;	/* set if we're being paced by umlsim control */
+static int dont_tick = 0; /* signal whether to do_timer on timer interrupt */
+
+
+/* ----- Probe system activity --------------------------------------------- */
+
+
+/*
+ * Regarding locking, note that
+ *
+ * - we're in idle,
+ * - our system has no other interrupts than timer interrupts, and
+ * - nobody is sending a timer interrupt just now
+ *
+ * Therefore, no locking against local interrupts is needed. (If it was, the
+ * race conditions in the accesses below would be the least of out concerns.)
+ */
+
+
+/*
+ * "got_work_without_tick" tests whether there is work pending that needs an
+ * interrupt, but that does not require the jiffie clock to tick.
+ */
+
+static int got_work_without_tick(void)
+{
+	return softirq_pending(smp_processor_id()) & ~(1UL << TIMER_SOFTIRQ);
+}
+
+
+/*
+ * "got_work_with_tick" tests whether there is work pending that needs an
+ * interrupt, and that will also advance the jiffie clock.
+ */
+
+static int got_work_with_tick(void)
+{
+	return softirq_pending(smp_processor_id()) & (1UL << TIMER_SOFTIRQ);
+}
+
+
+/*
+ * Getting idle despite having work to do was briefly discussed on l-k.
+ * For now, let's play it safe and explicitly get out of idle if we find any
+ * other process.
+ *
+ * Update: since we no longer run directly from the idle thread, it's perfectly
+ * normal to encounter other runnable processes (in addition to the idle
+ * thread) every once in a while.
+ */
+
+static int other_runnable(void)
+{
+	return nr_running() > 1; /* @@@ reconsider for SMP */
+}
+
+
+/* ----- Time arithmetic --------------------------------------------------- */
+
+
+static void ts_add(const struct timespec *a,const struct timespec *b,
+  struct timespec *res)
+{
+	res->tv_sec = a->tv_sec+b->tv_sec;
+	res->tv_nsec = a->tv_nsec+b->tv_nsec;
+	if (res->tv_nsec >= NSEC_PER_SEC) {
+		res->tv_nsec -= NSEC_PER_SEC;
+		res->tv_sec++;
+	}
+}
+
+
+static inline int ts_lt(const struct timespec *a,const struct timespec *b)
+{
+	if (a->tv_sec < b->tv_sec) return 1;
+	if (a->tv_sec > b->tv_sec) return 0;
+	return a->tv_nsec < b->tv_nsec;
+}
+
+
+/* ----- Interface to umlsim control --------------------------------------- */
+
+/*
+ * Do not change this function ! umlsim makes some very detailed assumptions on
+ * how "umlsim_idle" works.
+ */
+
+
+const struct timespec *umlsim_idle(int inactive,
+    const struct timespec *next_timer);
+
+const struct timespec *umlsim_idle(int inactive,
+    const struct timespec *next_timer)
+{
+	static struct timespec simulation_time;
+	int time_changed = 0;
+
+#ifdef DBG
+printk("umlsim_idle(inactive %d,next_timer %lu.%09lu)\n",
+  inactive,
+  next_timer ? (unsigned long) next_timer->tv_sec : 0UL,
+  next_timer ? (unsigned long) next_timer->tv_nsec : 0UL);
+#endif
+	MARKER(break_here,inactive,next_timer,simulation_time,time_changed);
+#ifdef DBG
+printk("umlsim_idle -> %lu.%09lu\n",
+  time_changed ? (unsigned long) simulation_time.tv_sec : 0UL,
+  time_changed ? (unsigned long) simulation_time.tv_nsec : 0UL);
+#endif
+	return time_changed ? &simulation_time : NULL;
+}
+
+
+/* ----- Next simulation event --------------------------------------------- */
+
+
+static void do_tick(int tick)
+{
+	TRACE("do_tick");
+#ifdef DBG
+printk("do_tick(%d): jiffies %lu\n",tick,jiffies);
+#endif
+	if (tick) last_tick = umlsim_now;
+	else dont_tick = 1;
+	umlsim_timer_interrupt();
+}
+
+
+static int advance_time(void)
+{
+	struct timespec next_tick;
+
+	ts_add(&last_tick,&jiffie_ts,&next_tick);
+	/*
+	 * jiffies+1, because reaching (and not only passing) a timer's
+	 * expiration time will trigger it
+	 */
+	while (jiffies+1 < next_timer_jiffies()) {
+		if (use_umlsim_idle && ts_lt(&next_sync,&next_tick)) return 0;
+		umlsim_now = next_tick;
+		if (got_work_with_tick()) {
+			do_tick(1);
+			return 1;
+		}
+		jiffies_64++;
+		last_tick = umlsim_now;
+		ts_add(&umlsim_now,&jiffie_ts,&next_tick);
+	}
+	umlsim_now = next_tick;
+	do_tick(1);
+	return 1;
+}
+
+
+extern const struct timespec *umlsim_idle_msg(int inactive,
+    const struct timespec *next_timer);
+
+
+static int be_idle(int inactive)
+{
+	const struct timespec *next_now;
+	struct timespec timer;
+
+	if (!use_umlsim_idle) return 0;
+#ifdef DBG
+printk("be_idle: jiff %lu next_t %lu\n",jiffies,next_timer_jiffies());
+#endif
+	jiffies_to_timespec(got_work_with_tick() ? jiffies+1 :
+	    next_timer_jiffies(),&timer);
+	if (umlsim_fds[0] == -1) next_now = umlsim_idle(inactive,&timer);
+	else next_now = umlsim_idle_msg(inactive,&timer);
+	if (next_now) next_sync = *next_now;
+	return !!next_now;
+}
+
+
+static void kernel_is_idle(void)
+{
+	static int inactive = 0;
+	static int time_uptodate = 1;
+	  /* make sure we don't leave idle until we've polled the timers */
+
+#ifdef DBG
+printk("kernel_is_idle: %lu.%09lu\n",
+  (unsigned long) last_tick.tv_sec,(unsigned long) last_tick.tv_nsec);
+#endif
+	if (time_uptodate) {
+		time_uptodate = !be_idle(inactive);
+		inactive = 1;
+	}
+	inactive = !other_runnable() && inactive;
+	if (got_work_without_tick()) {
+		inactive = 0;
+		do_tick(0);
+		return;
+	}
+	if (advance_time()) inactive = 0;
+	else time_uptodate = 1;
+}
+
+
+/* ----- Kernel taps ------------------------------------------------------- */
+
+
+extern void __towards_do_timer(struct pt_regs *regs);
+
+void __wrap_do_timer(struct pt_regs *regs)
+{
+	TRACE("__wrap_do_timer");
+	if (dont_tick) dont_tick = 0;
+	else __towards_do_timer(regs);
+}
+
+
+extern void __towards_do_gettimeofday(struct timeval *tv);
+
+void __wrap_do_gettimeofday(struct timeval *tv)
+{
+	TRACE("__wrap_do_gettimeofday");
+	if (umlsim_real_time) __towards_do_gettimeofday(tv);
+	else {
+		tv->tv_sec = umlsim_now.tv_sec;
+		tv->tv_usec = umlsim_now.tv_nsec/NSEC_PER_USEC;
+	}
+}
+
+
+/* ----- Pseudo idle thread ------------------------------------------------ */
+
+
+unsigned long umlsim_stat_other;
+unsigned long umlsim_stat_notick;
+unsigned long umlsim_stat_idle;
+
+
+static int kumlsim_idled(void *unused)
+{
+	daemonize("kumlsim_idled");
+	current->flags |= PF_IOTHREAD;
+	current->prio = current->static_prio = MAX_PRIO-1;
+	for (;;) {
+		yield();
+		if (other_runnable()) {
+			umlsim_stat_other++;
+			continue;
+		}
+		if (got_work_without_tick()) {
+			umlsim_stat_notick++;
+			continue;
+		}
+		umlsim_stat_idle++;
+		kernel_is_idle();
+	}
+}
+
+
+/* ----- Initialization ---------------------------------------------------- */
+
+
+static int __init umlsim_init(void)
+{
+	if (!umlsim_real_time) {
+		printk(KERN_INFO "Using virtual time%s%s\n",
+		    use_umlsim_idle ? " with umlsim" : "",
+		    umlsim_fds[0] == -1 ? "" : " (direct messages)");
+		if (kernel_thread(kumlsim_idled,NULL,CLONE_KERNEL) < 0) {
+			printk(KERN_ERR "kumlsim_idled failed\n");
+			return NOTIFY_BAD;
+		}
+	}
+	return NOTIFY_OK;
+}
+
+
+extern unsigned long loops_per_jiffy;
+extern int sync;
+
+
+static int __init set_umlsim_fds(const char *str)
+{
+	char *end;
+	int tmp;
+
+	if (*str != ',')
+		return 0;
+	tmp = simple_strtol(str+1,&end,10);
+	if (*end != ',')
+		return 0;
+	umlsim_fds[0] = tmp;
+	umlsim_fds[1] = simple_strtol(end+1,&end,10);
+	return 1;
+}
+
+
+static int __init set_vtime(char *str)
+{
+	TRACE("set_vtime");
+	if (!strncmp(str,"=umlsim",7)) {
+		use_umlsim_idle = 1;
+		if (str[7])
+			if (!set_umlsim_fds(str+7))
+				printk(KERN_ERR "invalid: vtime=%s\n",str);
+	}
+	umlsim_real_time = 0;
+	jiffies_to_timespec(1,&jiffie_ts);
+	loops_per_jiffy = 1;
+	sync = 1; /* make "disk" (UBD) activity synchronous */
+	return 1;
+}
+
+
+/*
+ * Basically, run as soon as we can create processes.
+ */
+arch_initcall(umlsim_init);
+
+__setup("vtime",set_vtime);
+
+__uml_help(set_vtime,
+"vtime[=umlsim]\n"
+"    Use virtual time instead of real time. This can either be in\n"
+"    standalone mode (just 'vtime'), or with umlsim ('vtime=umlsim').\n"
+"    Standalone mode is usually only good for testing. In umlsim mode,\n"
+"    the kernel will only run if under umlsim control. See\n"
+"    http://umlsim.sourceforge.net/ for further information.\n\n");
--- linux-2.5.69/arch/um/kernel/umlsim_user.c.orig	Tue May 27 02:22:06 2003
+++ linux-2.5.69/arch/um/kernel/umlsim_user.c	Sun Jun  1 01:37:32 2003
@@ -0,0 +1,135 @@
+/*
+ * umlsim_user.c - User-space side of UML simulator support
+ * 
+ * Written 2002,2003 by Werner Almesberger
+ * Copyright 2002 Werner Almesberger
+ * Copyright 2003 California Institute of Technology
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#define UMLSIM_USER /* work around weird include conflict */
+#include "umlsim.h"
+
+
+#if 0
+#define __TRACE(s) write(2,s,sizeof(s)-1)
+#define TRACE(s) __TRACE(s "\r\n")
+#else
+#define TRACE(s)
+#endif
+
+
+/*
+ * We don't put "umlsim_now" into umlsim.h, because it requires linux/time.h or
+ * sys/time.h, so it wouldn't be safe to share the header file between kernel
+ * and UML user space.
+ */
+
+extern struct timespec umlsim_now;
+
+
+/* ----- Message-passing idle handler -------------------------------------- */
+
+
+const struct timespec *umlsim_idle_msg(int inactive,
+    const struct timespec *next_timer)
+{
+	static struct timespec ts;
+	void *pos;
+	int len;
+
+	TRACE("umlsim_idle_msg");
+	if (next_timer)
+		ts = *next_timer;
+	else
+		ts.tv_sec = ts.tv_nsec = 0;
+	/*
+	 * The art of cheating, and avoiding to define a nice, clean message
+	 * structure.
+	 */
+	if (inactive) ts.tv_nsec |= 1 << 31;
+	pos = &ts;
+	len = sizeof(ts);
+	while (len) {
+		int wrote;
+
+		wrote = write(umlsim_fds[1],pos,len);
+		if (wrote < 0) {
+			perror("umlsim_idle_msg: write");
+			exit(1);
+		}
+		pos += wrote;
+		len -= wrote;
+	}
+	while (1) {
+		pos = &ts;
+		len = sizeof(ts);
+		while (len) {
+			int got;
+
+			got = read(umlsim_fds[0],pos,len);
+			if (got < 0) {
+				if (errno == EINTR)
+					continue;
+				perror("umlsim_idle_msg: read");
+				exit(1);
+			}
+			if (!got) {
+				fprintf(stderr,"umlsim_idle_msg: EOF\n");
+				exit(1);
+			}
+			pos += got;
+			len -= got;
+		}
+		if (ts.tv_nsec != ~0)
+			break;
+		__asm__ __volatile__("int3"); /* @@@ FIXME */
+	}
+	return ts.tv_sec || ts.tv_nsec ? &ts : NULL;
+}
+
+
+/* ----- UML taps ---------------------------------------------------------- */
+
+
+extern int __towards_setitimer(int which,const struct itimerval *value,
+    struct itimerval *ovalue);
+
+int __wrap_setitimer(int which,const struct itimerval *value,
+    struct itimerval *ovalue)
+{
+	TRACE("__wrap_setitimer");
+	if (!umlsim_real_time &&
+	    (which == ITIMER_REAL || which == ITIMER_VIRTUAL))
+		return 0;
+	return __towards_setitimer(which,value,ovalue);
+}
+
+
+extern int __towards_gettimeofday(struct timeval *tv,struct timezone *tz);
+
+int __wrap_gettimeofday(struct timeval *tv,struct timezone *tz)
+{
+	TRACE("__wrap_gettimeofday");
+	if (umlsim_real_time) return __towards_gettimeofday(tv,tz);
+	tv->tv_sec = umlsim_now.tv_sec;
+	tv->tv_usec = umlsim_now.tv_nsec/1000;
+	return 0;
+}
+
+
+/* ----- Send one timer interrupt ------------------------------------------ */
+
+
+void umlsim_timer_interrupt(void)
+{
+	TRACE("umlsim_timer_interrupt");
+	raise(SIGVTALRM);
+}
--- linux-2.5.69/arch/um/kernel/umlsim_inline.c.orig	Tue May 27 02:22:06 2003
+++ linux-2.5.69/arch/um/kernel/umlsim_inline.c	Tue May 27 02:22:06 2003
@@ -0,0 +1,31 @@
+/*
+ * umlsim_inline.c - Out-of-line instances of common inline functions
+ * 
+ * Written 2003 by Werner Almesberger
+ * Copyright 2003 California Institute of Technology
+ */
+
+/*
+ * Must be compiled with -fkeep-inline-functions -Wno-unused-function 
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/tcp.h>
+
+
+/*
+ * __this_fixmap_does_not_exist should be removed when inlining, but since
+ * we're inlining everything, optimizations like this one can be missed.
+ */
+
+void __this_fixmap_does_not_exist(void)
+{
+	panic("__this_fixmap_does_not_exist called\n");
+}
+
+
+/*
+ * That's all folks !
+ */
