summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-12-16 16:20:43 +0000
committerjdike <jdike>2003-12-16 16:20:43 +0000
commit84189f5812ea327088d31dcc635ada16ecbd1b6d (patch)
treef15911c63d9a314e70b9740fa9df12b2e6c2535b
parent80d67ec87b45db723eeec2f72b371a1726f6ce32 (diff)
downloaduml-history-84189f5812ea327088d31dcc635ada16ecbd1b6d.tar.gz
Added Sapan's real-time clock patch.
-rw-r--r--Documentation/Configure.help9
-rw-r--r--arch/um/config.in1
-rw-r--r--arch/um/include/kern_util.h2
-rw-r--r--arch/um/include/user_util.h1
-rw-r--r--arch/um/kernel/skas/trap_user.c4
-rw-r--r--arch/um/kernel/time.c37
-rw-r--r--arch/um/kernel/time_kern.c43
-rw-r--r--arch/um/sys-i386/bugs.c83
-rw-r--r--arch/um/sys-i386/time.c24
9 files changed, 176 insertions, 28 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 96669d2..d17d25c 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -15699,6 +15699,15 @@ CONFIG_TTY_LOG
Say 'N' unless you are setting up a UML honeypot or otherwise know that
you want this option.
+UML real-time clock support
+CONFIG_UML_REAL_TIME_CLOCK
+ This option ties the UML clock to the host clock, so that time passes at
+ the same rate as on the host, regardless of how much CPU time the UML is
+ getting. This should normally be enabled. The exception would be if you're
+ debugging UML. In this case, time spent staring at the debugger with UML
+ stopped will cause lots of timer ticks to be backed up, and UML will spent
+ lots of time calling the timer when it is finally continued.
+
Microtek USB scanner support
CONFIG_USB_MICROTEK
Say Y here if you want support for the Microtek X6USB and
diff --git a/arch/um/config.in b/arch/um/config.in
index e738e57..a28534b 100644
--- a/arch/um/config.in
+++ b/arch/um/config.in
@@ -49,6 +49,7 @@ int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
bool 'Highmem support' CONFIG_HIGHMEM
bool '/proc/mm' CONFIG_PROC_MM
int 'Kernel stack size order' CONFIG_KERNEL_STACK_ORDER 2
+bool 'Real-time Clock' CONFIG_UML_REAL_TIME_CLOCK
endmenu
mainmenu_option next_comment
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 26627ee..6c39cfd 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -107,6 +107,8 @@ extern void arch_switch(void);
extern void free_irq(unsigned int, void *);
extern int um_in_interrupt(void);
extern int cpu(void);
+extern unsigned long long time_stamp(void);
+
#endif
/*
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 929576b..a94c461 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -83,6 +83,7 @@ extern void check_sigio(void);
extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
extern void write_sigio_workaround(void);
extern void arch_check_bugs(void);
+extern int cpu_feature(char *what, char *buf, int len);
extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
extern int can_do_skas(void);
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
index 0906f65..ef45cb9 100644
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/kernel/skas/trap_user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -41,8 +41,6 @@ void user_signal(int sig, union uml_pt_regs *regs)
{
struct signal_info *info;
- if(sig == SIGVTALRM)
- missed_ticks[cpu()]++;
regs->skas.is_user = 1;
regs->skas.fault_addr = 0;
regs->skas.fault_type = 0;
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 34e16dc..7a6f766 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -4,6 +4,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
@@ -78,8 +79,44 @@ void idle_timer(void)
set_interval(ITIMER_REAL);
}
+static long get_host_hz(void)
+{
+ char mhzline[16], *end;
+ int ret, mult, mhz, rest, len;
+
+ ret = cpu_feature("cpu MHz", mhzline,
+ sizeof(mhzline) / sizeof(mhzline[0]));
+ if(!ret)
+ panic ("Could not get host MHZ");
+
+ mhz = strtoul(mhzline, &end, 10);
+
+ /* This business is to parse a floating point number without using
+ * floating types.
+ */
+
+ rest = 0;
+ mult = 0;
+ if(*end == '.'){
+ end++;
+ len = strlen(end);
+ if(len < 6)
+ mult = 6 - len;
+ else if(len > 6)
+ end[6] = '\0';
+ rest = strtoul(end, NULL, 10);
+ while(mult-- > 0)
+ rest *= 10;
+ }
+
+ return(1000000 * mhz + rest);
+}
+
+int host_hz = 0;
+
void time_init(void)
{
+ host_hz = get_host_hz();
if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
panic("Couldn't set SIGVTALRM handler");
set_interval(ITIMER_VIRTUAL);
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index b45f75f..8570a03 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -35,13 +35,47 @@ int timer_irq_inited = 0;
*/
int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
+static int first_tick;
+static unsigned long long prev_tsc;
+static long long delta; /* Deviation per interval */
+
+extern int host_hz;
+
void timer_irq(union uml_pt_regs *regs)
{
- int cpu = current->processor, ticks = missed_ticks[cpu];
+ unsigned long long ticks = 0;
- if(!timer_irq_inited) return;
- missed_ticks[cpu] = 0;
- while(ticks--) do_IRQ(TIMER_IRQ, regs);
+ if(!timer_irq_inited){
+ /* This is to ensure that ticks don't pile up when
+ * the timer handler is suspended */
+ first_tick = 0;
+ return;
+ }
+
+ if(first_tick){
+#if defined(CONFIG_UML_REAL_TIME_CLOCK)
+ unsigned long long tsc;
+ /* We've had 1 tick */
+ tsc = time_stamp();
+
+ delta += tsc - prev_tsc;
+ prev_tsc = tsc;
+
+ ticks += (delta * HZ) / host_hz;
+ delta -= (ticks * host_hz) / HZ;
+#else
+ ticks = 1;
+#endif
+ }
+ else {
+ prev_tsc = time_stamp();
+ first_tick = 1;
+ }
+
+ while(ticks > 0){
+ do_IRQ(TIMER_IRQ, regs);
+ ticks--;
+ }
}
void boot_timer_handler(int sig)
@@ -159,7 +193,6 @@ int __init timer_init(void)
__initcall(timer_init);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index fe4cbdb..d39750a 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -48,44 +48,79 @@ static char token(int fd, char *buf, int len, char stop)
return(c);
}
-static int check_cpu_feature(char *feature, int *have_it)
+static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
{
- char buf[MAXTOKEN], c;
- int fd, len = sizeof(buf)/sizeof(buf[0]), n;
-
- printk("Checking for host processor %s support...", feature);
- fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
- if(fd < 0){
- printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
- return(0);
- }
+ int n;
+ char c;
- *have_it = 0;
- buf[len - 1] = '\0';
+ scratch[len - 1] = '\0';
while(1){
- c = token(fd, buf, len - 1, ':');
- if(c <= 0) goto out;
+ c = token(fd, scratch, len - 1, ':');
+ if(c <= 0)
+ return(0);
else if(c != ':'){
printk("Failed to find ':' in /proc/cpuinfo\n");
- goto out;
+ return(0);
}
- if(!strncmp(buf, "flags", strlen("flags"))) break;
+ if(!strncmp(scratch, key, strlen(key)))
+ return(1);
do {
n = os_read_file(fd, &c, sizeof(c));
if(n != sizeof(c)){
printk("Failed to find newline in "
"/proc/cpuinfo, err = %d\n", -n);
- goto out;
+ return(0);
}
} while(c != '\n');
}
+ return(0);
+}
+
+int cpu_feature(char *what, char *buf, int len)
+{
+ int fd, ret = 0;
+
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ if(!find_cpuinfo_line(fd, what, buf, len)){
+ printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
+ goto out_close;
+ }
+
+ token(fd, buf, len, '\n');
+ ret = 1;
+
+ out_close:
+ os_close_file(fd);
+ return(ret);
+}
+
+static int check_cpu_flag(char *feature, int *have_it)
+{
+ char buf[MAXTOKEN], c;
+ int fd, len = sizeof(buf)/sizeof(buf[0]);
+
+ printk("Checking for host processor %s support...", feature);
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ *have_it = 0;
+ if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
+ goto out;
c = token(fd, buf, len - 1, ' ');
if(c < 0) goto out;
else if(c != ' '){
- printk("Failed to find ':' in /proc/cpuinfo\n");
+ printk("Failed to find ' ' in /proc/cpuinfo\n");
goto out;
}
@@ -106,6 +141,9 @@ static int check_cpu_feature(char *feature, int *have_it)
return(1);
}
+#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
+ * for some people.
+ */
static void disable_lcall(void)
{
struct modify_ldt_ldt_s ldt;
@@ -119,10 +157,13 @@ static void disable_lcall(void)
if(err)
printk("Failed to disable lcall7 - errno = %d\n", errno);
}
+#endif
void arch_init_thread(void)
{
+#if 0
disable_lcall();
+#endif
}
void arch_check_bugs(void)
@@ -134,8 +175,10 @@ void arch_check_bugs(void)
"checks\n");
return;
}
- if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
- if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
+ if(check_cpu_flag("cmov", &have_it))
+ cpu_has_cmov = have_it;
+ if(check_cpu_flag("xmm", &have_it))
+ cpu_has_xmm = have_it;
}
int arch_handle_signal(int sig, union uml_pt_regs *regs)
diff --git a/arch/um/sys-i386/time.c b/arch/um/sys-i386/time.c
new file mode 100644
index 0000000..a6a5ba7
--- /dev/null
+++ b/arch/um/sys-i386/time.c
@@ -0,0 +1,24 @@
+/*
+ * sys-i386/time.c
+ * Created 25.9.2002 Sapan Bhatia
+ *
+ */
+
+unsigned long long time_stamp(void)
+{
+ unsigned long low, high;
+
+ asm("rdtsc" : "=a" (low), "=d" (high));
+ return((((unsigned long long) high) << 32) + low);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */