diff options
author | jdike <jdike> | 2003-12-16 16:20:43 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-12-16 16:20:43 +0000 |
commit | 84189f5812ea327088d31dcc635ada16ecbd1b6d (patch) | |
tree | f15911c63d9a314e70b9740fa9df12b2e6c2535b | |
parent | 80d67ec87b45db723eeec2f72b371a1726f6ce32 (diff) | |
download | uml-history-84189f5812ea327088d31dcc635ada16ecbd1b6d.tar.gz |
Added Sapan's real-time clock patch.
-rw-r--r-- | Documentation/Configure.help | 9 | ||||
-rw-r--r-- | arch/um/config.in | 1 | ||||
-rw-r--r-- | arch/um/include/kern_util.h | 2 | ||||
-rw-r--r-- | arch/um/include/user_util.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/skas/trap_user.c | 4 | ||||
-rw-r--r-- | arch/um/kernel/time.c | 37 | ||||
-rw-r--r-- | arch/um/kernel/time_kern.c | 43 | ||||
-rw-r--r-- | arch/um/sys-i386/bugs.c | 83 | ||||
-rw-r--r-- | arch/um/sys-i386/time.c | 24 |
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: + */ |