systime: introducing system time based on time stamp counter/global timer, removing...
authorAdam Turowski <adam.turowski@inf.ethz.ch>
Mon, 28 Nov 2016 11:44:42 +0000 (12:44 +0100)
committerAdam Turowski <adam.turowski@inf.ethz.ch>
Mon, 28 Nov 2016 11:48:50 +0000 (12:48 +0100)
Signed-off-by: Adam Turowski <adam.turowski@inf.ethz.ch>

37 files changed:
devices/ia32.dev
devices/xapic.dev
include/arch/arm/barrelfish_kpi/unknown_arch.h
include/barrelfish/systime.h [new file with mode: 0644]
include/barrelfish_kpi/dispatcher_shared.h
include/barrelfish_kpi/types.h
kernel/Hakefile
kernel/arch/arm/exn.c
kernel/arch/armv7/a9_gt.c
kernel/arch/armv7/init.c
kernel/arch/armv7/plat_a9mpcore.c
kernel/arch/armv7/syscall.c
kernel/arch/x86/apic.c
kernel/arch/x86/pit.c
kernel/arch/x86/startup_x86.c
kernel/arch/x86/syscall.c
kernel/arch/x86/timing.c
kernel/arch/x86_64/init.c
kernel/arch/x86_64/irq.c
kernel/arch/x86_64/syscall.c
kernel/dispatch.c
kernel/include/arch/armv7/a9_gt.h
kernel/include/arch/x86/apic.h
kernel/include/arch/x86/global.h
kernel/include/arch/x86/pit.h
kernel/include/dispatch.h
kernel/include/kernel.h
kernel/include/systime.h [new file with mode: 0644]
kernel/kcb.c
kernel/schedule_rbed.c
kernel/syscall.c
kernel/systime.c [new file with mode: 0644]
kernel/wakeup.c
lib/barrelfish/Hakefile
lib/barrelfish/deferred.c
lib/barrelfish/init.c
lib/barrelfish/systime.c [new file with mode: 0644]

index 7e7d632..26e8a46 100644 (file)
@@ -10,8 +10,8 @@
  * ia32.dev
  *
  * DESCRIPTION: ia32 Architectural definitions, including Architectural MSRs
- * 
- * Numbers in comments refer to the Intel Architecture Manual, August 2007 
+ *
+ * Numbers in comments refer to the Intel Architecture Manual, August 2007
  */
 
 device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
@@ -39,7 +39,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        vec_gp = 13     "general protection fault";
        vec_pf = 14     "page fault";
        //              15 reserved to intel
-   
+
        vec_mf = 16     "x87 FPU floating-point error";
        vec_ac = 17     "alignment check";
        vec_mc = 18     "machine check";
@@ -61,7 +61,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
 
     // 7.11.5
     register mon_filter_size msr(0x06) "Monitor/Mwait filter size" type(uint64);
-    
+
     // Appendix B.1
     register platform_id ro msr(0x17) "Platform ID" {
        _       50;
@@ -92,7 +92,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        _              1 mbz;
        region_size    13 "Bytes that should be allocated for VMXON and VMCS regions";
        _              3;
-       paddr_width    1 "Physical address width Limited to 32 Bits";   
+       paddr_width    1 "Physical address width Limited to 32 Bits";
        dual_mon       1 "Dual-monitor treatment supported";
        mem_type       4 "Memory tpe used to access VMCS with VMREAD/VMWRITE";
        instr_info_io  1 "INS/OUTS info is reported in VM-exit instruction-information";
@@ -101,12 +101,12 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
     };
 
     // Capability Reporting Registers for VMX Controls
-    register vmx_pinbased_ctls ro msr(0x481) "Pin-based Controls" type(uint64);     
+    register vmx_pinbased_ctls ro msr(0x481) "Pin-based Controls" type(uint64);
     register vmx_ppbased_ctls ro msr(0x482) "Primary Processor-based Controls" type(uint64);
     register vmx_exit_ctls ro msr(0x483) "VM-exit Controls" type(uint64);
     register vmx_entry_ctls ro msr(0x484) "VM-entry Controls" type(uint64);
     register vmx_spbased_ctls ro msr(0x48b) "Secondary Processor-based Controls" type(uint64);
-     
+
     // Capability Reporting Registers for VMX Flex Controls
     register vmx_true_pinbased_ctls ro msr(0x48d) "Pin-based Flex Controls" type(uint64);
     register vmx_true_ppbased_ctls ro msr(0x48e) "Primary Processor-based Flex Controls" type(uint64);
@@ -143,8 +143,8 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        invvpid_sct    1 "Support single-context INVVPID type";
        invvpid_act    1 "Support all-context INVVPID type";
        invvpid_scrgt  1 "Support single-context-retaining-globals INVVPID type";
-       _              20; 
-    };        
+       _              20;
+    };
 
     register bios_updt_trig rw msr(0x79) "BIOS update trigger" type(uint64);
     register bios_sign_id rw msr(0x8b) "BIOS update signature" type(uint64);
@@ -210,12 +210,12 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        _               61;
     };
 
-    // 14.3.1.3 
+    // 14.3.1.3
     constants mcg_ctl_val width(64) "Global MC control values" {
        mc_enable       = 1s;
        mc_disable      = 0x0;
     };
-    register mcg_ctl rw msr(0x17b) "Global machine check control" 
+    register mcg_ctl rw msr(0x17b) "Global machine check control"
        type(mcg_ctl_val);
 
     // 14.3.2.5
@@ -254,8 +254,8 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        tbes            2 type(tbtrk) "Threshold-based error status";
        _               2 mbz; // Seems to need to be written zero to
                               // work (otherwise a GPF) but doesn't
-                              // always read as zero on 
-                              // some AMD-based processors. 
+                              // always read as zero on
+                              // some AMD-based processors.
        pcc             1 "Processor context corrupt";
        addrv           1 "MCi_ADDR register valid";
        miscv           1 "MCi_MISC register valid";
@@ -266,14 +266,14 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
     };
     regarray mc_addr rwzc msr(0x402)[5; 4] "Machine check addr" type(uint64);
     regarray mc_misc rwzc msr(0x403)[5; 4] "Machine check misc" type(uint64);
-    
+
 
     /*
      * ***********************
      * Debugging and performance
      * ***********************
      */
-    
+
     // 18.5.1
     register debugctl rw msr(0x1d9) "Debug control" {
        lbr                     1 "Last branch/int/exception";
@@ -285,13 +285,13 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        bts_off_os              1 "BTS off in OS";
        bts_off_usr             1 "BTS off in user code";
        freeze_lbrs_on_pmi      1;
-       freeze_perfmon_on_pmi   1; 
+       freeze_perfmon_on_pmi   1;
        _                       19;
     };
 
     // 18.10
     register tsc msr(0x10) "Time stamp counter" type(uint64);
-    
+
     // 18.12.1.1
     regtype perfevtsel "Perfmon event select" {
        evsel           8 "Event select";
@@ -322,7 +322,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
     register fixed_ctr2 rw msr(0x30b) "Fixed-funct. counter 2" type(fixed_ctr);
 
     //345 perf_capabilities
-    
+
     //18.12.2.1
     register fixed_ctr_ctl msr(0x38d) "Fixed counter control" {
        enos0           1 "Enable 0 for OS";
@@ -338,7 +338,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        _               1;
        pmi2            1 "Enable PMI on overflow 2";
        _               52;
-    }; 
+    };
 
     regtype perf_global "Perfmon global status/overflow" {
        pmc0            1 "PMC0 overflow";
@@ -352,9 +352,9 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        condchgd        1 "Condition changed";
     };
 
-    register perf_global_status ro msr(0x38e) "Perfmon global status" 
+    register perf_global_status ro msr(0x38e) "Perfmon global status"
        type(perf_global);
-    register perf_global_over rwzc msr(0x390) "Perfmon global overlflow control" 
+    register perf_global_over rwzc msr(0x390) "Perfmon global overlflow control"
        type(perf_global);
 
     register perf_global_ctrl msr(0x38f) "Perfmon global control" {
@@ -398,11 +398,11 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        ret     16 "SYSRET CS and SS";
     };
 
-    register lstar msr(0xc0000082) "Long mode Syscall target address" 
+    register lstar msr(0xc0000082) "Long mode Syscall target address"
        type(uint64);
 
     register cstar msr(0xc0000083) "Compatibility mode Syscall target address"
-        type(uint64);  
+        type(uint64);
 
     register fmask msr(0xc0000084) "SYSCALL EFLAGS mask" {
        v       32 "Value";
@@ -542,7 +542,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        rv      1 ro "Reading valid";
        _       32;
     };
-    
+
 
     /*
      * ***********************
@@ -692,5 +692,7 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
         avail  12 "Available";
         nx     1  "Np execute";
      };
-    
+
+    register tsc_deadline rw msr(0x6e0) "TSC deadline" type(uint64);
+
 };
index db3bec1..3e08ddc 100644 (file)
@@ -10,7 +10,7 @@
  * xapic.dev
  *
  * DESCRIPTION: Local eXtended APIC hardware description
- * 
+ *
  * Numbers in comments refer to the Intel Software Development Manual
  * volume 3, October 2007.
  */
@@ -41,8 +41,9 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
 
   // 8.5.1
   constants timer_mode "Timer mode" {
-    one_shot   = 0;
-    periodic   = 1;
+    one_shot     = 0;
+    periodic     = 1;
+    tsc_deadline = 2;
   };
 
   constants int_mask "Interrupt mask" {
@@ -56,11 +57,11 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
     status      1 "Delivery status";
     _           3;
     mask        1 type(int_mask) "Masked";
-    mode        1 type(timer_mode) "Mode";
-    _           14;
+    mode        2 type(timer_mode) "Mode";
+    _           13;
   };
 
-  constants vdm "Vector delivery mode" { 
+  constants vdm "Vector delivery mode" {
     fixed   = 0b000 "Fixed";
     lowest  = 0b001 "Lowest priority";
     smi     = 0b010 "SMI";
@@ -90,7 +91,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
   register lvt_lint0 rw addr(base, 0x0350) type (lvt_lint);
   register lvt_lint1 rw addr(base, 0x0360) type (lvt_lint);
 
-  register lvt_err rw addr(base, 0x0370) { 
+  register lvt_err rw addr(base, 0x0370) {
     vector      8 "Vector";
     _           4;
     status      1 "Delivery status";
@@ -108,7 +109,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
     mask        1 type(int_mask) "Masked";
     _           15;
   };
-  
+
   register lvt_perf_cnt rw addr(base, 0x0340) type (lvt_mon);
   register lvt_thermal rw addr(base, 0x0330) type (lvt_mon);
 
@@ -177,7 +178,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
     _           24;
     dest        8 "Destination field";
   };
-  
+
   /*
    * the xeon phi has a slightly different register layout than normal apic
    */
@@ -191,7 +192,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
     _           24;
     log_id      8 "Logical APIC ID";
   };
-  
+
   register ldr_xeon_phi rw also  addr(base, 0x00d0) "Logical Destination" {
     _           16;
     log_id      16 "Logical APIC ID";
@@ -222,7 +223,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
 
   // 8.8.5
   register eoi wo addr(base, 0x00b0) "End Of Interrupt" type(uint32);
-  
+
   // 8.9
   register svr rw addr(base, 0x00f0) "Spurious Interrupt Vector Register" {
     vector      8 "Vector";
@@ -233,7 +234,7 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
 
   /*
    * AMD extensions: see AMD64 Architecture Programmer's Manual,
-   * vol. 2 rev 3.14 (September 2007). 
+   * vol. 2 rev 3.14 (September 2007).
    */
 
   // 16.7.1
@@ -259,9 +260,8 @@ device xapic lsbfirst ( addr base ) "Local APIC" {
     vector     8 "Vector";
     _          24 mbz;
   };
-  
+
   // 16.7.3
   regarray ier ro addr(base, 0x0480) [8; 0x10] "IER" type(uint32);
 
 };
-
index c639a44..27083af 100644 (file)
@@ -37,10 +37,11 @@ static inline void cache_flush_range(void *base, size_t len)
 
 static inline uint64_t rdtsc(void)
 {
-    /* XXX - only the lower 32 bits - the interface needs to be improved. */
-    uint32_t timestamp;
-    errval_t err= sys_debug_hardware_timer_read(&timestamp);
-    (void)err;
+    uint64_t timestamp;
+    errval_t err;
+
+    // temporary solution, this should be a direct timer read
+    err = sys_debug_hardware_global_timer_read(&timestamp);
     assert(err_is_ok(err));
     return timestamp;
 }
diff --git a/include/barrelfish/systime.h b/include/barrelfish/systime.h
new file mode 100644 (file)
index 0000000..5d63a85
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * \file
+ * \brief System time
+ */
+
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
+ */
+
+#ifndef BARRELFISH_SYSTIME_H
+#define BARRELFISH_SYSTIME_H
+
+#include <barrelfish_kpi/generic_arch.h> /* systime_t */
+
+/// Frequency of the system time ticks (systime)
+extern systime_t systime_frequency;
+
+/**
+ * Get the current system time from a hardware clock
+ */
+static inline systime_t systime_now(void)
+{
+    return rdtsc();
+}
+
+/**
+ * Convert nanoseconds to a system time ticks
+ */
+systime_t ns_to_systime(uint64_t nanoseconds);
+
+/**
+ * Convert a system time ticks to nanoseconds
+ */
+uint64_t systime_to_ns(systime_t time);
+
+#endif // BARRELFISH_SYSTIME_H
index dbabeee..8a4ac4b 100644 (file)
@@ -57,6 +57,7 @@ struct dispatcher_shared_generic {
     uint32_t    fpu_used;                       ///< Was FPU used while disabled?
     uint32_t    fpu_trap;                       ///< State of FPU trap
 
+    uint64_t    systime_frequency;              ///< Systime frequency
     coreid_t    curr_core_id;                   ///< Core id of current core, in this part so kernel can update
 #ifdef __k1om__
     uint8_t     xeon_phi_id;
index 41fbacf..baf573f 100644 (file)
@@ -124,7 +124,7 @@ typedef uint64_t perfmon_event_t;
 // Performance mask
 typedef uint64_t perfmon_mask_t;
 
-/// Absolute system time (in microseconds)
+/// Absolute system wallclock time in ticks
 typedef uint64_t systime_t;
 #define PRIuSYSTIME PRIu64
 #define PRIxSYSTIME PRIx64
index e5edc13..2bbfbdb 100644 (file)
@@ -47,7 +47,8 @@ let
                "syscall.c",
                "wakeup.c",
                "useraccess.c",
-               "coreboot.c" ]
+               "coreboot.c",
+               "systime.c" ]
              ++ (if Config.microbenchmarks then ["microbenchmarks.c"] else [])
              ++ (if Config.oneshot_timer then ["timer.c"] else [])
   common_libs = [ "getopt", "mdb_kernel" ]
@@ -128,6 +129,7 @@ let
                 "arch/x86_64/page_mappings_arch.c",
                 "arch/x86/apic.c",
                 "arch/x86/pic.c",
+                "arch/x86/pit.c",
                 "arch/x86/cmos.c",
                 "arch/x86/misc.c",
                 "arch/x86/serial.c",
index ed466bd..7744926 100644 (file)
@@ -21,6 +21,7 @@
 #include <wakeup.h>
 #include <irq.h>
 #include <gic.h>
+#include <systime.h>
 
 void handle_user_page_fault(lvaddr_t fault_address,
                             arch_registers_state_t* save_area,
@@ -32,7 +33,7 @@ void handle_user_page_fault(lvaddr_t fault_address,
     // XXX
     assert(dcb_current != NULL);
     assert((struct dispatcher_shared_arm *)(dcb_current->disp) == disp);
-    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, save_area->named.pc)) { 
+    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, save_area->named.pc)) {
         assert(save_area == dispatcher_get_trap_save_area((dispatcher_handle_t)disp));
         dcb_current->disabled = true;
     } else {
@@ -100,7 +101,7 @@ void handle_user_undef(lvaddr_t fault_address,
     // XXX
     assert(dcb_current != NULL);
     assert((struct dispatcher_shared_arm *)(dcb_current->disp) == disp);
-    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, save_area->named.pc)) { 
+    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, save_area->named.pc)) {
         assert(save_area == dispatcher_get_trap_save_area((dispatcher_handle_t)disp));
         dcb_current->disabled = true;
     } else {
@@ -266,14 +267,14 @@ void handle_fiq_kernel(arch_registers_state_t* save_area, uintptr_t fault_pc)
     panic("FIQ Interrupt in the kernel");
 }
 
-void handle_fiq(arch_registers_state_t* save_area, 
-                uintptr_t fault_pc, 
+void handle_fiq(arch_registers_state_t* save_area,
+                uintptr_t fault_pc,
                 struct dispatcher_shared_generic *disp)
 {
     panic("FIQ interrupt from user mode");
 }
 
-void handle_irq_kernel(arch_registers_state_t* save_area, 
+void handle_irq_kernel(arch_registers_state_t* save_area,
                        uintptr_t fault_pc)
 {
     /* In-kernel interrupts are bugs, except if we'd gone to sleep in
@@ -288,8 +289,8 @@ void handle_irq_kernel(arch_registers_state_t* save_area,
     handle_irq(save_area, fault_pc, NULL);
 }
 
-void handle_irq(arch_registers_state_t* save_area, 
-                uintptr_t fault_pc, 
+void handle_irq(arch_registers_state_t* save_area,
+                uintptr_t fault_pc,
                 struct dispatcher_shared_arm *disp)
 {
     // XXX
@@ -298,7 +299,7 @@ void handle_irq(arch_registers_state_t* save_area,
     // XXX
     if(dcb_current != NULL) {
         assert((struct dispatcher_shared_arm *)(dcb_current->disp) == disp);
-        if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, fault_pc)) { 
+        if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, fault_pc)) {
             assert(save_area ==
                    dispatcher_get_disabled_save_area(
                        (dispatcher_handle_t)disp));
@@ -316,13 +317,11 @@ void handle_irq(arch_registers_state_t* save_area,
     irq = gic_get_active_irq();
     debug(SUBSYS_DISPATCH, "IRQ %"PRIu32" while %s\n", irq,
           dcb_current->disabled ? "disabled": "enabled" );
-    
+
     // Offer it to the timer
     if (timer_interrupt(irq)) {
         // Timer interrupt, timer_interrupt() acks it at the timer.
-        assert(kernel_ticks_enabled);
-        kernel_now += kernel_timeslice;
-        wakeup_check(kernel_now);
+        wakeup_check(systime_now());
         dispatch(schedule());
     }
     // this is the (still) unacknowledged startup interrupt sent by the BSP
index 37c1d8c..b46fc25 100644 (file)
@@ -16,6 +16,7 @@
 #include <kernel.h>
 #include <paging_kernel_arch.h>
 #include <dev/cortex_a9_gt_dev.h>
+#include <systime.h>
 
 static cortex_a9_gt_t a9_gt;
 static bool initialized = false;
@@ -34,14 +35,12 @@ void a9_gt_init(lpaddr_t addr)
     initialized = true;
     MSG("initialized at 0x%"PRIxLVADDR"\n", gt_base);
 
-    // enable auto increment
-    cortex_a9_gt_TimerControl_auto_increment_wrf(&a9_gt, 0x1);
-
-    // reset timer (TRM 4.4.4)
-    cortex_a9_gt_TimerControl_timer_enable_wrf(&a9_gt, 0x0);
-    cortex_a9_gt_TimerCounterLow_wr(&a9_gt, 0x0);
-    cortex_a9_gt_TimerCounterHigh_wr(&a9_gt, 0x0);
+    // set the global timer
     cortex_a9_gt_TimerControl_timer_enable_wrf(&a9_gt, 0x1);
+    cortex_a9_gt_TimerControl_comp_enable_wrf(&a9_gt, 0x0);
+    cortex_a9_gt_TimerControl_int_enable_wrf(&a9_gt, 0x1);
+    cortex_a9_gt_TimerControl_auto_increment_wrf(&a9_gt, 0x0);
+    cortex_a9_gt_TimerControl_prescale_wrf(&a9_gt, 0x0);
 }
 
 uint64_t a9_gt_read(void)
@@ -65,3 +64,11 @@ uint32_t a9_gt_read_high(void)
 {
     return cortex_a9_gt_TimerCounterHigh_rd(&a9_gt);
 }
+
+void a9_gt_set_comparator(uint64_t timeout)
+{
+    cortex_a9_gt_TimerControl_comp_enable_wrf(&a9_gt, 0x0);
+    cortex_a9_gt_TimerComparatorLow_wr(&a9_gt, timeout);
+    cortex_a9_gt_TimerComparatorHigh_wr(&a9_gt, timeout >> 32);
+    cortex_a9_gt_TimerControl_comp_enable_wrf(&a9_gt, 0x1);
+}
index 0b8bddf..0e8bab5 100644 (file)
@@ -66,7 +66,7 @@ static struct cmdarg cmdargs[] = {
     { "debugPort",   ArgType_UInt, { .uinteger = (void *)0 } },
     { "loglevel",    ArgType_Int,  { .integer  = (void *)0 } },
     { "logmask",     ArgType_Int,  { .integer  = (void *)0 } },
-    { "timeslice",   ArgType_Int,  { .integer  = (void *)0 } },
+    { "timeslice",   ArgType_UInt,  { .uinteger = (void *)0 } },
     { "periphclk",   ArgType_UInt, { .uinteger = (void *)0 } },
     { "periphbase",  ArgType_UInt, { .uinteger = (void *)0 } },
     { "timerirq"  ,  ArgType_UInt, { .uinteger = (void *)0 } },
@@ -80,7 +80,7 @@ init_cmdargs(void) {
     cmdargs[1].var.uinteger= &serial_debug_port;
     cmdargs[2].var.integer=  &kernel_loglevel;
     cmdargs[3].var.integer=  &kernel_log_subsystem_mask;
-    cmdargs[4].var.integer=  &kernel_timeslice;
+    cmdargs[4].var.uinteger= &config_timeslice;
     cmdargs[5].var.uinteger= &periphclk;
     cmdargs[6].var.uinteger= &periphbase;
     cmdargs[7].var.uinteger= &timerirq;
@@ -221,7 +221,7 @@ arch_init(struct arm_core_data *boot_core_data,
                min(MAXCMDLINE-1, strlen(mb_cmdline)));
         core_data->cmdline_buf[MAXCMDLINE-1]= '\0';
     }
-    
+
     MSG("Multiboot info:\n");
     MSG(" info header at 0x%"PRIxLVADDR"\n",       (lvaddr_t)mb);
     MSG(" mods_addr is P:0x%"PRIxLPADDR"\n",       (lpaddr_t)mb->mods_addr);
@@ -254,7 +254,7 @@ arch_init(struct arm_core_data *boot_core_data,
     MSG("Parsing command line\n");
     init_cmdargs();
     parse_commandline((const char *)core_data->cmdline, cmdargs);
-    kernel_timeslice = min(max(kernel_timeslice, 20), 1);
+    config_timeslice = min(max(config_timeslice, 1), 20);
 
     errval = serial_debug_init();
     if (err_is_fail(errval)) {
@@ -272,7 +272,7 @@ arch_init(struct arm_core_data *boot_core_data,
     }
 
     MSG("Enabling timers\n");
-    timers_init(kernel_timeslice);
+    timers_init(config_timeslice);
 
     MSG("Enabling cycle counter user access\n");
     /* enable user-mode access to the performance counter */
@@ -290,13 +290,13 @@ arch_init(struct arm_core_data *boot_core_data,
 
 #if 0
 /**
- * \brief Initialization for the BSP (the first core to be booted). 
+ * \brief Initialization for the BSP (the first core to be booted).
  * \param pointer address of \c multiboot_info
  */
-static void bsp_init( void *pointer ) 
+static void bsp_init( void *pointer )
 {
     struct multiboot_info *mb = pointer;
-    
+
     MSG("We seem to be a BSP; multiboot info:\n");
     MSG(" mods_addr is 0x%"PRIxLVADDR"\n",       (lvaddr_t)mb->mods_addr);
     MSG(" mods_count is 0x%"PRIxLVADDR"\n",      (lvaddr_t)mb->mods_count);
@@ -308,7 +308,7 @@ static void bsp_init( void *pointer )
 }
 
 /**
- * \brief Initialization on a non-BSP (second and successive cores). 
+ * \brief Initialization on a non-BSP (second and successive cores).
  * \param pointer address of the global structure set up by \c bsp_init
  */
 static void nonbsp_init( void *pointer )
index 1d619db..046a914 100644 (file)
@@ -23,6 +23,7 @@
 #include <init.h>
 #include <paging_kernel_arch.h>
 #include <platform.h>
+#include <systime.h>
 
 #define MSG(format, ...) \
     printk( LOG_NOTE, "CortexA9 platform: "format, ## __VA_ARGS__ )
@@ -79,8 +80,8 @@ platform_get_core_count(void) {
 
 static cortex_a9_pit_t tsc;
 
-/* See TRM 4.2.3 */
-#define LOCAL_TIMER_IRQ 29
+/* See TRM 4.3 */
+#define GLOBAL_TIMER_IRQ 27
 
 void
 timers_init(int timeslice) {
@@ -93,29 +94,18 @@ timers_init(int timeslice) {
     /* Global timer: use the Cortex-A9 Global Timer
        (see Cortex-A9 MPCore TRM 4.3). */
     a9_gt_init(platform_get_gt_address());
-
+    gic_enable_interrupt(GLOBAL_TIMER_IRQ, 0, 0, 0, 0);
     /* Discover the clock rate. */
     a9_probe_tsc();
     assert(tsc_hz != 0);
 
-    /* Write counter reload value.  Divide by 1000, as timeslice is in ms. */
-    uint32_t reload = (timeslice * tsc_hz) / 1000;
+    systime_frequency = tsc_hz;
+
     MSG("System counter frequency is %uHz.\n", tsc_hz);
-    MSG("Timeslice interrupt every %u ticks (%dms).\n", reload, timeslice);
-    cortex_a9_pit_TimerLoad_wr(&tsc, reload);
-
-    /* Prescaler value to 1 - run at PERIPHCLK to match the global timer. */
-    cortex_a9_pit_TimerControl_prescale_wrf(&tsc, 0);
-    /* Enable interrupt generation. */
-    cortex_a9_pit_TimerControl_int_enable_wrf(&tsc, 1);
-    /* Automatic reload. */
-    cortex_a9_pit_TimerControl_auto_reload_wrf(&tsc, 1);
-    /* Clear any pending event */
-    cortex_a9_pit_TimerIntStat_event_flag_wrf(&tsc, 1);
-    /* Enable the timeslice interrupt. */
-    gic_enable_interrupt(LOCAL_TIMER_IRQ, 0, 0, 0, 0);
-    /* Enable the timer. */
-    cortex_a9_pit_TimerControl_timer_enable_wrf(&tsc, 1);
+    /* Set kernel timeslice value, timeslice is in ms. */
+    kernel_timeslice = ns_to_systime(timeslice * 1000000);
+    MSG("Timeslice interrupt every %llu system ticks (%dms).\n", kernel_timeslice, timeslice);
+    systime_set_timeout(systime_now() + kernel_timeslice);
 }
 
 uint64_t
@@ -128,12 +118,12 @@ timestamp_freq(void) {
     return tsc_hz;
 }
 
-bool
-timer_interrupt(uint32_t irq) {
-    if(irq == LOCAL_TIMER_IRQ) {
-        /* Clear the flag at the timer. */
-        cortex_a9_pit_TimerIntStat_event_flag_wrf(&tsc, 1);
-
+bool timer_interrupt(uint32_t irq) {
+    if (irq == GLOBAL_TIMER_IRQ) {
+#ifndef CONFIG_ONESHOT_TIMER
+        // Set next trigger
+        systime_set_timeout(systime_now() + kernel_timeslice);
+#endif
         /* Ack the interrupt at the controller. */
         gic_ack_irq(irq);
         return 1;
@@ -141,3 +131,13 @@ timer_interrupt(uint32_t irq) {
 
     return 0;
 }
+
+systime_t systime_now(void)
+{
+    return a9_gt_read();
+}
+
+void systime_set_timeout(systime_t timeout)
+{
+    a9_gt_set_comparator(timeout);
+}
index 3cf488b..5087fdc 100644 (file)
@@ -27,6 +27,7 @@
 #include <useraccess.h>
 #include <platform.h>
 #include <startup_arch.h>
+#include <systime.h>
 
 // helper macros  for invocation handler definitions
 #define INVOCATION_HANDLER(func) \
@@ -45,7 +46,7 @@ func( \
 
 
 __attribute__((noreturn))
- void sys_syscall(arch_registers_state_t* context, 
+ void sys_syscall(arch_registers_state_t* context,
                  uint32_t disabled,
                  struct dispatcher_shared_arm *disp);
 __attribute__((noreturn))
@@ -1225,7 +1226,7 @@ static struct sysret handle_debug_syscall(int msg)
             break;
 
         case DEBUG_TIMESLICE_COUNTER_READ:
-            retval.value = kernel_now;
+            retval.value = systime_now();
             break;
 
         case DEBUG_HARDWARE_TIMER_READ:
@@ -1264,7 +1265,7 @@ static struct sysret handle_debug_syscall(int msg)
        //  r2  = kernel address of dispatcher
        //  r3  = scratch value
 __attribute__((noreturn))
-void sys_syscall(arch_registers_state_t* context, 
+void sys_syscall(arch_registers_state_t* context,
                 uint32_t disabled,
                 struct dispatcher_shared_arm *disp)
 {
@@ -1274,7 +1275,7 @@ void sys_syscall(arch_registers_state_t* context,
     // XXX
     assert(dcb_current != NULL);
     assert((struct dispatcher_shared_arm *)(dcb_current->disp) == disp);
-    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, context->named.pc)) { 
+    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, context->named.pc)) {
        assert(context == dispatcher_get_disabled_save_area((dispatcher_handle_t)disp));
        dcb_current->disabled = true;
     } else {
@@ -1374,4 +1375,3 @@ void sys_syscall(arch_registers_state_t* context,
 
     resume(context);
 }
-
index 45a3639..300ea90 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <kernel.h>
+#include <systime.h>
 #include <arch/x86/apic.h>
 #include <arch/x86/start_aps.h>
 #include <paging_kernel_arch.h>
 #define APIC_PAGE_SIZE          4096
 #define APIC_DEFAULT_PRIORITY   0x0000
 
+/// Ratio of APIC frequency to systime frequency * 2^32
+uint64_t apic_systime_frequency_ratio;
+
 /**
  * The kernel's APIC ID.
  */
 uint8_t apic_id;
 
 /**
- * True iff we're on the BSP
+ * True if we're on the BSP
  */
 bool apic_bsp = true;
 
 static xapic_t apic;
 
+/// TSC deadline functionality
+static bool use_tsc_deadline = false;
+
 /**
  * \brief Initializes the local APIC timer.
  *
@@ -47,8 +54,9 @@ void apic_timer_init(bool masked, bool periodic)
 {
     xapic_lvt_timer_t t = xapic_lvt_timer_initial;
     t = xapic_lvt_timer_vector_insert(t, APIC_TIMER_INTERRUPT_VECTOR);
-    t = xapic_lvt_timer_mask_insert(t, masked ? xapic_masked : xapic_not_masked );
-    t = xapic_lvt_timer_mode_insert(t, periodic ? xapic_periodic : xapic_one_shot);
+    t = xapic_lvt_timer_mask_insert(t, masked ? xapic_masked : xapic_not_masked);
+    t = xapic_lvt_timer_mode_insert(t, periodic ? xapic_periodic :
+        (use_tsc_deadline && !masked ? xapic_tsc_deadline : xapic_one_shot));
     xapic_lvt_timer_wr(&apic, t);
 }
 
@@ -208,6 +216,17 @@ void apic_init(void)
         apic_base_msr = ia32_apic_base_global_insert(apic_base_msr, 1);
         ia32_apic_base_wr(NULL,apic_base_msr);
     }
+
+    uint32_t eax, ebx, ecx, edx;
+
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+    if (ecx & (1 << 24)) { // check for TSC deadline functionality
+        use_tsc_deadline = true;
+    }
+    // cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
+    // if (edx && (1 << 8)) { // check if TSC is invariant
+    //     printf("TSC invariant\n");
+    // }
 }
 
 /** \brief This function sends an IPI
@@ -388,3 +407,31 @@ void apic_disable(void) {
     apic_base_msr = ia32_apic_base_global_insert(apic_base_msr, 0);
     ia32_apic_base_wr(NULL, apic_base_msr);
 }
+
+static uint32_t systime_to_apic_ticks(systime_t ticks)
+{
+    uint64_t q, r;
+
+    q = ticks >> 32;
+    r = ticks & 0xffffffff;
+    uint64_t rt = q * apic_systime_frequency_ratio +
+        ((r * apic_systime_frequency_ratio) >> 32);
+    return MIN(rt, UINT32_MAX);
+}
+
+void systime_set_timeout(systime_t timeout)
+{
+    if (use_tsc_deadline) { // we have TSC deadline
+        ia32_tsc_deadline_wr(NULL, timeout);
+    } else { // fallback to APIC timer
+        uint32_t apic_ticks = 1;
+
+        systime_t now = systime_now();
+        if (timeout > now) {
+            apic_ticks = systime_to_apic_ticks(timeout - now);
+            if (apic_ticks == 0)
+                apic_ticks = 1;
+        }
+        apic_timer_set_count(apic_ticks);
+    }
+}
index 9769e82..3c2d85e 100644 (file)
@@ -31,12 +31,12 @@ static struct lpc_timer_t timer;        ///< Mackerel state for timer registers
  * \param count  Count for oneshot timer, rate for ticker
  * \param periodic True for a periodic timer, false for oneshot
  */
-void pit_timer0_set(uint16_t count, bool periodic)
+void pit_timer0_set(uint16_t count, bool periodic, bool only_lsb)
 {
     struct lpc_timer_tcw_t tcw = {
         .bcd = 0,                       // Binary mode (no BCD)
         .mode = periodic ? lpc_timer_rtgen : lpc_timer_oseoc, // Operating mode
-        .rwsel = lpc_timer_lmsb,        // First MSB, then LSB
+        .rwsel = only_lsb ? lpc_timer_lsb: lpc_timer_lmsb,
         .select = lpc_timer_c0          // Select counter 0
     };
 
@@ -45,7 +45,8 @@ void pit_timer0_set(uint16_t count, bool periodic)
 
     if (count > 0) {
         // Set the count/rate (LSB, then MSB)
-        lpc_timer_cntacc0_wr(&timer, count & 0xff);
+        if (!only_lsb)
+            lpc_timer_cntacc0_wr(&timer, count & 0xff);
         lpc_timer_cntacc0_wr(&timer, count >> 8);
     }
 }
@@ -83,8 +84,13 @@ uint16_t pit_timer0_read(void)
     return val;
 }
 
+uint8_t pit_timer0_read_lsb(void)
+{
+    return lpc_timer_cntacc0_rd(&timer);
+}
+
 void pit_init(void)
 {
     lpc_timer_initialize(&timer, TIMER_IOBASE);
-    pit_timer0_set(0, false);
+    pit_timer0_set(0, false, false);
 }
index 4fd528a..de844b4 100644 (file)
@@ -432,7 +432,7 @@ static struct cmdarg cmdargs[] = {
     {"loglevel", ArgType_Int, { .integer = &kernel_loglevel }},
     {"logmask", ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
     {"ticks", ArgType_Bool, { .boolean = &kernel_ticks_enabled }},
-    {"timeslice", ArgType_Int, { .integer = &kernel_timeslice }},
+    {"timeslice", ArgType_UInt, { .uinteger = &config_timeslice }},
     {"serial", ArgType_Int, { .integer = &serial_portbase }},
     {"bsp_coreid", ArgType_Int, { .integer = &bsp_coreid }},
     {NULL, 0, {NULL}}
index 2f47829..96d7614 100644 (file)
@@ -74,7 +74,7 @@ struct sysret sys_monitor_handle_sync_timer(uint64_t synctime)
     }
 
     while(rdtsc() < synctime);
-    timing_apic_timer_set_ms(kernel_timeslice);
+    timing_apic_timer_set_ms(config_timeslice);
     tsc_lasttime = rdtsc();
     scheduler_reset_time();
 
index a135e2c..a71f5d8 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <string.h>
 #include <kernel.h>
+#include <systime.h>
 #include <arch/x86/apic.h>
 #include <arch/x86/rtc.h>
 #include <arch/x86/pit.h>
@@ -24,7 +25,7 @@
 #include <xeon_phi.h>
 #endif
 
-static uint32_t tickspersec = 0;
+static uint32_t apic_frequency = 0;
 static uint64_t tscperms = 0;
 
 #if !defined(__k1om__)
@@ -32,19 +33,21 @@ static uint64_t tscperms = 0;
  * \brief Calibrates local APIC timer against RTC.
  * \return Local APIC timer ticks per RTC second.
  */
-static uint32_t calibrate_apic_timer_rtc(void)
+static uint32_t __attribute__((unused)) calibrate_apic_timer_rtc(uint64_t *ticks_per_ms)
 {
     // Set APIC timer to one-shot mode
     apic_timer_init(true, false);
     apic_timer_set_divide(xapic_by1);
     // Wait until start of new second
 
+    uint64_t tsc_start, tsc_end;
     uint8_t start = rtc_read_secs(), now;
     do {
         now = rtc_read_secs();
     } while(now == start);
 
     apic_timer_set_count(UINT32_MAX);
+    tsc_start = rdtsc();
 
     // Wait a second
     //uint32_t oldcount = UINT32_MAX;
@@ -52,7 +55,6 @@ static uint32_t calibrate_apic_timer_rtc(void)
     start = now;
     do {
         now = rtc_read_secs();
-
 #if 0
         // Assert timer never underflows
         // XXX: this fires on QEMU, because the APIC timer is driven directly by
@@ -66,11 +68,16 @@ static uint32_t calibrate_apic_timer_rtc(void)
 
     // Get new count
     uint32_t curcount = apic_timer_get_count();
+    tsc_end = rdtsc();
     assert(curcount != 0);
+    uint64_t ticks;
+
+    ticks = tsc_end - tsc_start;
+    *ticks_per_ms = ticks / 1000;
 
     uint32_t tps = UINT32_MAX - curcount;
     printk(LOG_NOTE, "Measured %"PRIu32" APIC timer counts in one RTC second, "
-           "%d data points.\n", tps, reads);
+           "%d data points. %ld ticks per ms\n", tps, reads, *ticks_per_ms);
 
     return tps;
 }
@@ -141,52 +148,48 @@ static uint32_t calibrate_pit_rtc(void)
     return ticks;
 }
 
+#endif
 /**
  * \brief Calibrates local APIC timer against PIT.
  * \return Local APIC timer ticks per PIT second.
  */
-static uint32_t calibrate_apic_timer_pit(void)
+static uint32_t calibrate_apic_timer_pit(systime_t *systime_freq)
 {
     // Set APIC timer to one-shot mode
-    xapic_lvt_timer_wr(&apic, (xapic_lvt_timer_t) {
-            .vector = APIC_TIMER_INTERRUPT_VECTOR,
-            .mask = xapic_masked,
-            .mode = xapic_one_shot }
-        );
-
+    apic_timer_init(true, false);
     apic_timer_set_divide(xapic_by1);
 
     // Calibrate against PIT
     pit_init();
-    pit_timer0_set(0xffff, false);
+    pit_timer0_set(0xffff, false, true); // only lsb
 
     // Start both timers
     apic_timer_set_count(UINT32_MAX);
 
-    // Wait a second (1,193,180 Ticks)
+    // Wait a second (1,193,182 ticks)
     uint16_t oldcnt = pit_timer0_read();
+    uint64_t timestamp = rdtsc();
     uint32_t ticks = 0;
     do {
         uint16_t cnt = pit_timer0_read();
-        if(cnt <= oldcnt) {
+        if (cnt <= oldcnt) {
             ticks += oldcnt - cnt;
         } else {
-            ticks += oldcnt + (0xffff - cnt);
+            ticks += oldcnt + 256 - cnt;
         }
         oldcnt = cnt;
-    } while(ticks < 1193180);
 
-    // Get new count
-    uint32_t curcount = xapic_cur_count_rd(&apic);
-    assert(curcount != 0);
+    } while (ticks < PIT_TIMER0_FREQUENCY);
 
-    uint32_t tps = UINT32_MAX - curcount;
-    printf("Measured %d APIC timer counts in one PIT second.\n",
-           tps);
+    uint64_t afreq = UINT32_MAX - apic_timer_get_count();
+    uint64_t sfreq = rdtsc() - timestamp;
 
-    return tps;
+    *systime_freq = sfreq;
+    printf("Measured APIC frequency: %ld Hz, systime frequency: %ld Hz\n",
+           afreq, sfreq);
+    return afreq;
 }
-#endif
+
 
 /// Number of measurement iterations
 #define MAX_ITERATIONS  100
@@ -195,11 +198,11 @@ static uint32_t calibrate_apic_timer_pit(void)
  * \brief Calibrates TSC against local APIC timer.
  * \return TSC ticks per local APIC timer tick.
  */
-static uint64_t calibrate_tsc_apic_timer(void)
+static uint64_t __attribute__((unused)) calibrate_tsc_apic_timer(void)
 {
     // Must tick with higher granularity than a millisecond
-    assert(tickspersec > 1000);
-    uint32_t ticksperms = tickspersec / 1000;
+    assert(apic_frequency > 1000);
+    uint32_t ticksperms = apic_frequency / 1000;
 
     // XXX: Let's hope this fits on the stack (reserve half the stack)
     /* assert(sizeof(uint64_t) * MAX_ITERATIONS < KERNEL_STACK_SIZE / 2); */
@@ -269,26 +272,16 @@ static uint64_t calibrate_tsc_apic_timer(void)
 void timing_apic_timer_set_ms(unsigned int ms)
 {
     // Must tick with higher granularity than a millisecond
-    assert(tickspersec > 1000);
-    assert(ms < UINT32_MAX / (tickspersec / 1000));
+    assert(apic_frequency > 1000);
+    assert(ms < UINT32_MAX / (apic_frequency / 1000));
 
     apic_timer_set_divide(xapic_by1);
-    apic_timer_set_count(ms * (tickspersec / 1000));
-}
-
-void arch_set_timer(systime_t t);
-void arch_set_timer(systime_t t)
-{
-    // systime_t is absolute time in ms,
-    // and the APIC time count registers are 32 bit
-    assert(t > kernel_now);
-    uint32_t ms = (t - kernel_now);
-    apic_timer_set_count(ms * (tickspersec / 1000));
+    apic_timer_set_count(ms * (apic_frequency / 1000));
 }
 
 uint32_t timing_get_apic_ticks_per_sec(void)
 {
-    return tickspersec;
+    return apic_frequency;
 }
 
 uint64_t timing_get_tsc_per_ms(void)
@@ -303,22 +296,29 @@ void timing_calibrate(void)
     if (CPU_IS_M5_SIMULATOR) {
         // Guess -- avoid delay of calibration
         printk(LOG_WARN, "Warning: using hard-coded timer calibration on M5\n");
-        tickspersec = 31250000;
-        tscperms = tickspersec/1000;
+        apic_frequency = 31250000;
+        tscperms = apic_frequency / 1000;
     } else {
         if(apic_is_bsp()) {
 #ifdef __k1om__
-            tickspersec = calibrate_apic_timer_k1om();
+            apic_frequency = calibrate_apic_timer_k1om();
+            tscperms = calibrate_tsc_apic_timer();
+            systime_frequency = tscperms * 1000;
 #else
-            tickspersec = calibrate_apic_timer_rtc();
+            apic_frequency = calibrate_apic_timer_pit(&systime_frequency);
 #endif
-            global->tickspersec = tickspersec;
-
-            tscperms = calibrate_tsc_apic_timer();
-            global->tscperms = tscperms;
+            global->apic_frequency = apic_frequency;
+            global->systime_frequency = systime_frequency;
         } else {
-            tickspersec = global->tickspersec;
-            tscperms = global->tscperms;
+            apic_frequency = global->apic_frequency;
+            systime_frequency = global->systime_frequency;
         }
+        tscperms = systime_frequency / 1000;
+        apic_systime_frequency_ratio = ((uint64_t)apic_frequency << 32) / systime_frequency;
     }
 }
+
+systime_t systime_now(void)
+{
+    return rdtsc();
+}
index 2ac940d..1b2baf3 100644 (file)
@@ -26,6 +26,7 @@
 #include <getopt/getopt.h>
 #include <exec.h>
 #include <kputchar.h>
+#include <systime.h>
 #include <arch/x86/conio.h>
 #include <arch/x86/pic.h>
 #include <arch/x86/apic.h>
@@ -483,7 +484,7 @@ static void  __attribute__ ((noreturn, noinline)) text_init(void)
 
     // do not remove/change this printf: needed by regression harness
     printf("Barrelfish CPU driver starting on x86_64 apic_id %u\n", apic_id);
-   
+
 
     if(apic_is_bsp()) {
         // Initialize classic (8259A) PIC
@@ -496,13 +497,12 @@ static void  __attribute__ ((noreturn, noinline)) text_init(void)
     // Initialize local APIC timer
     if (kernel_ticks_enabled) {
         timing_calibrate();
-        bool periodic = true;
-        #ifdef CONFIG_ONESHOT_TIMER
-        // we probably need a global variable like kernel_ticks_enabled
-        periodic = false;
-        #endif
-        apic_timer_init(false, periodic);
-        timing_apic_timer_set_ms(kernel_timeslice);
+        apic_timer_init(false, false);
+        apic_timer_set_divide(xapic_by1);
+        kernel_timeslice = ns_to_systime(config_timeslice * 1000000);
+#ifndef CONFIG_ONESHOT_TIMER
+        systime_set_timeout(systime_now() + kernel_timeslice);
+#endif
     } else {
         printk(LOG_WARN, "APIC timer disabled: NO timeslicing\n");
         apic_mask_timer();
index b43e937..dd96865 100644 (file)
@@ -69,6 +69,7 @@
 #include <kcb.h>
 #include <mdb/mdb_tree.h>
 #include <sys_debug.h>
+#include <systime.h>
 
 #include <dev/ia32_dev.h>
 
@@ -931,29 +932,6 @@ static __attribute__ ((used))
     __asm volatile("" :: "r" (arg0), "r" (arg1), "r" (arg2), "r" (arg3));
 }
 
-static void
-update_kernel_now(void)
-{
-    uint64_t tsc_now = rdtsc();
-    #ifdef CONFIG_ONESHOT_TIMER
-    uint64_t ticks = tsc_now - tsc_lasttime;
-    kernel_now += ticks / timing_get_tsc_per_ms();
-    #else // !CONFIG_ONESHOT_TIMER
-    // maintain compatibility with old behaviour. Not sure if it is
-    // actually needed. -AKK
-    //
-    // Ignore timeslice if it happens too closely (less than half
-    // of the TSC ticks that are supposed to pass) to the last.
-    // In that case we have just synced timers and see a spurious
-    // APIC timer interrupt.
-    if(tsc_now - tsc_lasttime >
-       (kernel_timeslice * timing_get_tsc_per_ms()) / 2) {
-        kernel_now += kernel_timeslice;
-    }
-    #endif // CONFIG_ONESHOT_TIMER
-    tsc_lasttime = tsc_now;
-}
-
 /// Handle an IRQ that arrived, either while in user or kernel mode (HLT)
 static __attribute__ ((used)) void handle_irq(int vector)
 {
@@ -975,6 +953,10 @@ static __attribute__ ((used)) void handle_irq(int vector)
     if (vector == APIC_TIMER_INTERRUPT_VECTOR) {
         // count time slices
         timer_fired ++;
+        static uint64_t last = 0;
+        systime_t now = systime_now();
+
+        last = now;
 
         // switch kcb every other timeslice
         if (!kcb_sched_suspended && timer_fired % 2 == 0 && kcb_current->next) {
@@ -984,9 +966,11 @@ static __attribute__ ((used)) void handle_irq(int vector)
 
         apic_eoi();
            assert(kernel_ticks_enabled);
-           update_kernel_now();
-        trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_TIMER, kernel_now);
-        wakeup_check(kernel_now+kcb_current->kernel_off);
+        trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_TIMER, now);
+        wakeup_check(now + kcb_current->kernel_off);
+#ifndef CONFIG_ONESHOT_TIMER
+        systime_set_timeout(now + kernel_timeslice);
+#endif
     } else if (vector == APIC_PERFORMANCE_INTERRUPT_VECTOR) {
         // Handle performance counter overflow
         // Reset counters
@@ -1037,7 +1021,7 @@ static __attribute__ ((used)) void handle_irq(int vector)
         // Update kernel_off for all KCBs
         struct kcb *k = kcb_current;
         do{
-            k->kernel_off = kernel_now;
+            k->kernel_off = systime_now();
             k = k->next;
         } while(k && k!=kcb_current);
         // Stop the core
index 6145909..17d007c 100644 (file)
@@ -24,6 +24,7 @@
 #include <paging_generic.h>
 #include <exec.h>
 #include <fpu.h>
+#include <systime.h>
 #include <arch/x86/x86.h>
 #include <arch/x86/apic.h>
 #include <arch/x86/global.h>
@@ -592,8 +593,8 @@ static struct sysret handle_io(struct capability *to, int cmd, uintptr_t *args)
     return sys_io(to, cmd, port, data);
 }
 
-static struct sysret handle_vmread(struct capability *to, 
-                                  int cmd, uintptr_t *args) 
+static struct sysret handle_vmread(struct capability *to,
+                                  int cmd, uintptr_t *args)
 {
 #if defined(__k1om__) || defined(CONFIG_SVM)
     return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
@@ -610,8 +611,8 @@ static struct sysret handle_vmread(struct capability *to,
 #endif
 }
 
-static struct sysret handle_vmwrite(struct capability *to, 
-                                   int cmd, uintptr_t *args) 
+static struct sysret handle_vmwrite(struct capability *to,
+                                   int cmd, uintptr_t *args)
 {
 #if defined(__k1om__) || defined(CONFIG_SVM)
     return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
@@ -628,8 +629,8 @@ static struct sysret handle_vmwrite(struct capability *to,
 #endif
 }
 
-static struct sysret handle_vmptrld(struct capability *to, 
-                                   int cmd, uintptr_t *args) 
+static struct sysret handle_vmptrld(struct capability *to,
+                                   int cmd, uintptr_t *args)
 {
 #if defined(__k1om__) || defined(CONFIG_SVM)
     return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
@@ -642,8 +643,8 @@ static struct sysret handle_vmptrld(struct capability *to,
 #endif
 }
 
-static struct sysret handle_vmclear(struct capability *to, 
-                                   int cmd, uintptr_t *args) 
+static struct sysret handle_vmclear(struct capability *to,
+                                   int cmd, uintptr_t *args)
 {
 #if defined(__k1om__) || defined(CONFIG_SVM)
     return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
@@ -737,7 +738,7 @@ handle_dispatcher_setup_guest (struct capability *to, int cmd, uintptr_t *args)
     }
 
 #ifndef CONFIG_SVM
-    // Initialize VMCS for the single virtual-CPU here instead of in 
+    // Initialize VMCS for the single virtual-CPU here instead of in
     // userspace, where the privilege level is not 0.
     err = initialize_vmcs(vmcb_cte->cap.u.frame.base);
     assert(err_is_ok(err));
@@ -1518,7 +1519,7 @@ struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
             break;
 
         case DEBUG_TIMESLICE_COUNTER_READ:
-            retval.value = kernel_now;
+            retval.value = systime_now();
             break;
 
         case DEBUG_FLUSH_CACHE:
index 7eb7501..f100539 100644 (file)
@@ -19,6 +19,7 @@
 #include <dispatch.h>
 #include <kcb.h>
 #include <wakeup.h>
+#include <systime.h>
 #include <barrelfish_kpi/syscalls.h>
 #include <barrelfish_kpi/lmp.h>
 #include <trace/trace.h>
 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
 
 /**
- * \brief The kernel timeslice given in milliseconds.
+ * \brief The kernel timeslice given in system ticks
  */
-int kernel_timeslice = CONFIG_TIMESLICE;
+systime_t kernel_timeslice;
+
+unsigned int config_timeslice = CONFIG_TIMESLICE;
 
 /// Counter for number of context switches
 uint64_t context_switch_counter = 0;
@@ -145,13 +148,6 @@ void __attribute__ ((noreturn)) dispatch(struct dcb *dcb)
     // If we have nothing to do we should call something other than dispatch
     if (dcb == NULL) {
         dcb_current = NULL;
-#if defined(__x86_64__) || defined(__i386__) || defined(__k1om__)
-        // Can this be moved into wait_for_interrupt?
-        // Or wait_for_nonscheduling_interrupt()?
-        if (!wakeup_is_pending()) {
-            apic_mask_timer();
-        }
-#endif
         wait_for_interrupt();
     }
 
@@ -177,7 +173,7 @@ void __attribute__ ((noreturn)) dispatch(struct dcb *dcb)
         dispatcher_get_disabled_save_area(handle);
 
     if(disp != NULL) {
-        disp->systime = kernel_now + kcb_current->kernel_off;
+        disp->systime = systime_now() + kcb_current->kernel_off;
     }
     TRACE(KERNEL, SC_YIELD, 1);
 
index eb98ee1..fd98b6d 100644 (file)
@@ -41,4 +41,7 @@ extern uint32_t tsc_hz;
 /* Platform-specific clock rate discovery. */
 void a9_probe_tsc(void);
 
+/// Set a global timer comparator
+void a9_gt_set_comparator(uint64_t timeout);
+
 #endif // __A9_GT_H__
index d4c2dd2..df3f809 100644 (file)
@@ -25,6 +25,8 @@
 #define APIC_ERROR_INTERRUPT_VECTOR             253
 #define APIC_SPURIOUS_INTERRUPT_VECTOR          254
 
+extern uint64_t apic_systime_frequency_ratio;
+
 void apic_init(void);
 void apic_send_init_assert(uint8_t destination, uint8_t destination_shorthand);
 void apic_send_init_deassert(void);
index 4884434..7b2fd02 100644 (file)
@@ -28,8 +28,8 @@ struct global {
         spinlock_t print;       ///< Lock for printing
     } locks;
 
-    uint32_t tickspersec;
-    uint32_t tscperms;
+    uint32_t apic_frequency;
+    systime_t systime_frequency;
 
     uint64_t padding[64];
     volatile uint64_t wait[8];
index f7e4e9b..94fa8c6 100644 (file)
 
 /// Period of LPC timer 0 counter, in nanoseconds
 #define PIT_TIMER0_PERIOD_NS    838
+#define PIT_TIMER0_FREQUENCY    1193182
 
 void pit_init(void);
-void pit_timer0_set(uint16_t count, bool periodic);
+void pit_timer0_set(uint16_t count, bool periodic, bool only_lsb);
 uint16_t pit_timer0_read(void);
+uint8_t pit_timer0_read_lsb(void);
 
 #endif
index a36bdee..8b36ba3 100644 (file)
@@ -54,8 +54,8 @@ struct dcb {
     struct dcb          *prev;          ///< Previous DCB in schedule
                                         /// (only valid iff CONFIG_SCHEDULER_RR)
 #if defined(CONFIG_SCHEDULER_RBED)
-    unsigned long       release_time, etime, last_dispatch;
-    unsigned long       wcet, period, deadline;
+    systime_t          release_time, etime, last_dispatch;
+    systime_t          wcet, period, deadline;
     unsigned short      weight;
     enum task_type      type;
 #endif
index c8a6396..246067d 100644 (file)
@@ -111,22 +111,20 @@ void kernel_startup_early(void);
 void kernel_startup(void) __attribute__ ((noreturn));
 
 /**
- * command-line option for kernel timeslice in milliseconds.
+ * kernel timeslice in system ticks
  */
-extern int kernel_timeslice;
+extern systime_t kernel_timeslice;
 
 /**
- * variable for gating timer interrupts.
+ * command-line option for kernel timeslice in milliseconds
  */
-extern bool kernel_ticks_enabled;
+extern unsigned int config_timeslice;
 
 /**
- * Current kernel epoch in number of kernel_timeslice elapsed.
- *
- * XXX AKK: shouldn't this be systime_t?
- * (It seems to count ms and not ticks anyway)
+ * variable for gating timer interrupts.
  */
-extern size_t kernel_now;
+extern bool kernel_ticks_enabled;
+
 
 extern lvaddr_t kernel_trace_buf;
 
diff --git a/kernel/include/systime.h b/kernel/include/systime.h
new file mode 100644 (file)
index 0000000..5e90e5e
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * \file
+ * \brief System time
+ */
+
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef __SYSTIME_H
+#define __SYSTIME_H
+
+#include <kernel.h> /* systime_t */
+
+/// Frequency of the system time ticks (systime)
+extern systime_t systime_frequency;
+
+/**
+ * Get the current system time from a hardware clock
+ */
+systime_t systime_now(void);
+
+/**
+ * Convert nanoseconds to a system time ticks
+ */
+systime_t ns_to_systime(uint64_t nanoseconds);
+
+/**
+ * Convert a system time ticks to nanoseconds
+ */
+uint64_t systime_to_ns(systime_t time);
+
+/**
+ * Set a point at which a timer interrupt should occur
+ * if it's in a past, trigger immediately
+ */
+void systime_set_timeout(systime_t timeout);
+
+#endif // __SYSTIME_H
index e330df7..83e6d33 100644 (file)
@@ -15,6 +15,7 @@
 #include <kernel.h>
 #include <kcb.h>
 #include <dispatch.h>
+#include <systime.h>
 
 // this is used to pin a kcb for critical sections
 bool kcb_sched_suspended = false;
@@ -42,7 +43,7 @@ errval_t kcb_remove(struct kcb *to_remove)
         if (to_remove->next->next == to_remove) {
             assert(to_remove->next->prev == to_remove);
             to_remove->next->next = to_remove->next->prev = NULL;
-        } 
+        }
         else {
             to_remove->prev->next = to_remove->next;
             to_remove->next->prev = to_remove->prev;
@@ -51,7 +52,7 @@ errval_t kcb_remove(struct kcb *to_remove)
         // intentionally leaving to_remove->next alone
         // so switch_kcb doesn't break
         to_remove->prev = NULL;
-        to_remove->kernel_off = kernel_now;
+        to_remove->kernel_off = systime_now();
 
         return SYS_ERR_OK;
     }
@@ -72,7 +73,7 @@ errval_t kcb_remove(struct kcb *to_remove)
             k->next = k->prev = NULL;
 
             // Update kernel_off & break out if we're done
-            k->kernel_off = kernel_now;
+            k->kernel_off = systime_now();
             return SYS_ERR_OK;
         }
     }
index e5df532..5048dd2 100644 (file)
@@ -60,6 +60,7 @@
 #       include <trace_definitions/trace_defs.h>
 #       include <timer.h> // update_sched_timer
 #       include <kcb.h>
+#include <systime.h>
 #endif
 
 #define SPECTRUM        1000000
@@ -105,7 +106,7 @@ static inline unsigned int u_actual_srt(struct dcb *dcb)
     }
 }
 
-static inline unsigned long deadline(struct dcb *dcb)
+static inline systime_t deadline(struct dcb *dcb)
 {
     return dcb->release_time + dcb->deadline;
 }
@@ -280,16 +281,13 @@ static void adjust_weights(void)
 static void set_best_effort_wcet(struct dcb *dcb)
 {
     unsigned int u_actual = do_resource_allocation(dcb);
-    unsigned long wcet_undiv = (kcb_current->n_be * kernel_timeslice * u_actual);
+    systime_t wcet_undiv = (kcb_current->n_be * kernel_timeslice * u_actual);
 
     // Assert we are never overloaded
     assert(kcb_current->u_hrt + kcb_current->u_srt + u_actual <= SPECTRUM);
 
     // Divide with proper rounding
-    dcb->wcet = wcet_undiv / SPECTRUM;
-    if(wcet_undiv % SPECTRUM > (SPECTRUM >> 1)) {
-        dcb->wcet++;
-    }
+    dcb->wcet = (wcet_undiv + SPECTRUM / 2) / SPECTRUM;
 }
 
 /**
@@ -300,15 +298,16 @@ static void set_best_effort_wcet(struct dcb *dcb)
 struct dcb *schedule(void)
 {
     struct dcb *todisp;
+    systime_t now = systime_now();
 
     // Assert we are never overloaded
     assert(kcb_current->u_hrt + kcb_current->u_srt + BETA <= SPECTRUM);
 
     // Update executed time of last dispatched task
     if(lastdisp != NULL) {
-        assert(lastdisp->last_dispatch <= kernel_now);
-        if(lastdisp->release_time <= kernel_now) {
-            lastdisp->etime += kernel_now -
+        assert(lastdisp->last_dispatch <= now);
+        if(lastdisp->release_time <= now) {
+            lastdisp->etime += now -
                 MAX(lastdisp->last_dispatch, lastdisp->release_time);
         }
     }
@@ -326,7 +325,7 @@ struct dcb *schedule(void)
         struct dispatcher_shared_generic *dst = \
             get_dispatcher_shared_generic(d->disp); \
         debug(SUBSYS_DISPATCH, "looking at '%s', release_time=%lu, kernel_now=%zu\n", \
-                dst->name, d->release_time, kernel_now); \
+                dst->name, d->release_time, now); \
     }while(0)
 #else
 #define PRINT_NAME(d) do{}while(0)
@@ -334,7 +333,7 @@ struct dcb *schedule(void)
 
     // Skip over all tasks released in the future, they're technically not
     // in the schedule yet. We just have them to reduce book-keeping.
-    while(todisp != NULL && todisp->release_time > kernel_now) {
+    while(todisp != NULL && todisp->release_time > now) {
         PRINT_NAME(todisp);
         todisp = todisp->next;
     }
@@ -357,24 +356,24 @@ struct dcb *schedule(void)
          * another BE task was removed while we already ran well into
          * our timeslice). In that case we need to re-release.
          */
-        if(deadline(todisp) < kernel_now) {
-            todisp->release_time = kernel_now;
+        if(deadline(todisp) < now) {
+            todisp->release_time = now;
         }
     }
 
     // Assert we never miss a hard deadline
-    if(todisp->type == TASK_TYPE_HARD_REALTIME && kernel_now > deadline(todisp)) {
-        panic("Missed hard deadline: now = %zu, deadline = %lu", kernel_now,
+    if(todisp->type == TASK_TYPE_HARD_REALTIME && now > deadline(todisp)) {
+        panic("Missed hard deadline: now = %zu, deadline = %lu", now,
               deadline(todisp));
         assert(false && "HRT task missed a dead line!");
     }
 
     // Deadline's can't be in the past (or EDF wouldn't work properly)
-    assert(deadline(todisp) >= kernel_now);
+    assert(deadline(todisp) >= now);
 
     // Dispatch first guy in schedule if not over budget
     if(todisp->etime < todisp->wcet) {
-        todisp->last_dispatch = kernel_now;
+        todisp->last_dispatch = now;
 
         // If nothing changed, run whatever ran last (task might have
         // yielded to another), unless it is blocked
@@ -392,7 +391,7 @@ struct dcb *schedule(void)
         #ifdef CONFIG_ONESHOT_TIMER
         // we might be able to do better than that...
         // (e.g., check if there is only one task in the queue)
-        update_sched_timer(kernel_now + (todisp->wcet - todisp->etime));
+        update_sched_timer(now + (todisp->wcet - todisp->etime));
         #endif
         return todisp;
     }
@@ -414,11 +413,11 @@ struct dcb *schedule(void)
     struct dcb *dcb = todisp;
     queue_remove(todisp);
     if(dcb->type != TASK_TYPE_BEST_EFFORT) {
-        if(kernel_now > dcb->release_time) {
+        if(now > dcb->release_time) {
             dcb->release_time += dcb->period;
         }
     } else {
-        dcb->release_time = kernel_now;
+        dcb->release_time = now;
     }
     dcb->etime = 0;
     queue_insert(dcb);
@@ -429,14 +428,17 @@ struct dcb *schedule(void)
 
 void schedule_now(struct dcb *dcb)
 {
-    if (dcb->release_time >= kernel_now) {
-        dcb->release_time = kernel_now;
+    systime_t now = systime_now();
+    if (dcb->release_time >= now) {
+        dcb->release_time = now;
     }
     dcb->deadline = 1;
 }
 
 void make_runnable(struct dcb *dcb)
 {
+    systime_t now = systime_now();
+
     // No-Op if already in schedule
     if(in_queue(dcb)) {
         return;
@@ -460,7 +462,7 @@ void make_runnable(struct dcb *dcb)
         kcb_current->w_be += dcb->weight;
         kcb_current->n_be++;
         dcb->deadline = dcb->period = kcb_current->n_be * kernel_timeslice;
-        dcb->release_time = kernel_now;
+        dcb->release_time = now;
         /* queue_sort(); */
         break;
 
@@ -483,9 +485,9 @@ void make_runnable(struct dcb *dcb)
               (kcb_current->u_hrt + kcb_current->u_srt + BETA) / (SPECTRUM / 100));
     }
 
-    if(dcb->release_time < kernel_now) {
+    if(dcb->release_time < now) {
         panic("Released in the past! now = %zu, release_time = %lu\n",
-              kernel_now, dcb->release_time);
+              now, dcb->release_time);
     }
     /* assert(dcb->release_time >= kernel_now); */
     dcb->etime = 0;
@@ -543,8 +545,9 @@ void scheduler_remove(struct dcb *dcb)
  */
 void scheduler_yield(struct dcb *dcb)
 {
+    systime_t now = systime_now();
     // For tasks not running yet, yield is a no-op
-    if(!in_queue(dcb) || dcb->release_time > kernel_now) {
+    if(!in_queue(dcb) || dcb->release_time > now) {
         return;
     }
 
@@ -560,7 +563,7 @@ void scheduler_yield(struct dcb *dcb)
 
     case TASK_TYPE_BEST_EFFORT:
         // Shuffle us around one time
-        dcb->release_time = kernel_now;
+        dcb->release_time = now;
         break;
     }
     dcb->etime = 0;
@@ -572,7 +575,6 @@ void scheduler_yield(struct dcb *dcb)
 void scheduler_reset_time(void)
 {
     trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_TIMER_SYNC, 0);
-    kernel_now = 0;
 
     // XXX: Currently, we just re-release everything now
     struct kcb *k = kcb_current;
index d7212f6..48c61ad 100644 (file)
@@ -35,6 +35,7 @@
 #include <trace_definitions/trace_defs.h>
 #include <kcb.h>
 #include <useraccess.h>
+#include <systime.h>
 
 errval_t sys_print(const char *str, size_t length)
 {
@@ -177,6 +178,9 @@ sys_dispatcher_setup(struct capability *to, capaddr_t cptr, uint8_t level,
         trace_new_boot_application(disp->name, (uintptr_t) dcb);
     }
 
+    // Setup systime frequency
+    disp->systime_frequency = systime_frequency;
+
     return SYSRET(SYS_ERR_OK);
 }
 
@@ -205,7 +209,7 @@ sys_dispatcher_properties(struct capability *to,
     dcb->deadline = deadline;
     dcb->wcet = wcet;
     dcb->period = period;
-    dcb->release_time = (release == 0) ? kernel_now : release;
+    dcb->release_time = (release == 0) ? systime_now() : release;
     dcb->weight = weight;
 
     make_runnable(dcb);
@@ -618,7 +622,7 @@ struct sysret sys_resize_l1cnode(struct capability *root, capaddr_t newroot_cptr
 struct sysret sys_yield(capaddr_t target)
 {
     dispatcher_handle_t handle = dcb_current->disp;
-    struct dispatcher_shared_generic *disp = 
+    struct dispatcher_shared_generic *disp =
         get_dispatcher_shared_generic(handle);
 
 
@@ -657,7 +661,7 @@ struct sysret sys_yield(capaddr_t target)
     // Remove from queue when no work and no more messages and no missed wakeup
     systime_t wakeup = disp->wakeup;
     if (!disp->haswork && disp->lmp_delivered == disp->lmp_seen
-        && (wakeup == 0 || wakeup > (kernel_now + kcb_current->kernel_off))) {
+        && (wakeup == 0 || wakeup > (systime_now() + kcb_current->kernel_off))) {
 
         trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_SCHED_REMOVE,
             (uint32_t)(lvaddr_t)dcb_current & 0xFFFFFFFF);
@@ -801,7 +805,7 @@ struct sysret sys_kernel_add_kcb(struct kcb *new_kcb)
     kcb_add(new_kcb);
 
     // update kernel_now offset
-    new_kcb->kernel_off -= kernel_now;
+    new_kcb->kernel_off -= systime_now();
     // reset scheduler statistics
     scheduler_reset_time();
     // update current core id of all domains
@@ -850,6 +854,6 @@ struct sysret sys_get_absolute_time(void)
     // of a second accuracy range.
     return (struct sysret) {
         .error = SYS_ERR_OK,
-        .value = kernel_now + kcb_current->kernel_off,
+        .value = systime_now() + kcb_current->kernel_off,
     };
 }
diff --git a/kernel/systime.c b/kernel/systime.c
new file mode 100644 (file)
index 0000000..7ab0747
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * \file
+ * \brief System time, constants and convertors
+ *
+ */
+
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <systime.h>
+
+/// Number of system ticks per one millisecond
+systime_t systime_frequency = 1;
+
+
+/// Convert nanoseconds to system ticks
+systime_t ns_to_systime(uint64_t nanoseconds)
+{
+    uint64_t q, r;
+
+    q = nanoseconds / 1000000000;
+    r = nanoseconds % 1000000000;
+
+    // Adding half a tick to round properly
+    return q * systime_frequency + (r * systime_frequency + 500000000) / 1000000000;
+}
+
+/// Convert system ticks to nanoseconds
+uint64_t systime_to_ns(systime_t time)
+{
+    systime_t q, r;
+
+    q = time / systime_frequency;
+    r = time % systime_frequency;
+
+    // Adding half a nanosecond to round properly
+    return q * 1000000000 + (r * 1000000000 + systime_frequency / 2) / systime_frequency;
+}
index bb8fb91..461b9ec 100644 (file)
@@ -17,6 +17,7 @@
 #include <kcb.h> // kcb_current->wakeup_queue_head
 #include <timer.h> // update_wakeup_timer()
 #include <wakeup.h>
+#include <systime.h>
 
 /* wrapper to change the head, and update the next wakeup tick */
 void wakeup_set_queue_head(struct dcb *h)
@@ -58,7 +59,6 @@ void wakeup_remove(struct dcb *dcb)
 void wakeup_set(struct dcb *dcb, systime_t waketime)
 {
     assert(dcb != NULL);
-    assert(waketime > (kernel_now + kcb_current->kernel_off));
 
     // if we're already enqueued, remove first
     wakeup_remove(dcb);
@@ -97,6 +97,7 @@ void wakeup_check(systime_t now)
         d->wakeup_time = 0;
         d->wakeup_prev = d->wakeup_next = NULL;
         make_runnable(d);
+        schedule_now(d);
     }
     if (d != NULL) {
         d->wakeup_prev = NULL;
index cf987e6..6d2d4e2 100644 (file)
@@ -27,7 +27,7 @@ let common_srcs = [ "capabilities.c", "init.c", "dispatch.c", "threads.c",
                     "slot_alloc/single_slot_alloc.c", "slot_alloc/slot_alloc.c",
                     "slot_alloc/range_slot_alloc.c", "slot_alloc/twolevel_slot_alloc.c",
                     "bulk_transfer.c", "trace.c", "resource_ctrl.c", "coreset.c",
-                    "inthandler.c", "deferred.c", "syscalls.c", "sys_debug.c"
+                    "inthandler.c", "deferred.c", "syscalls.c", "sys_debug.c", "systime.c"
                   ]
 in
 [(let arch_dir = "arch" </> archFamily arch
index 65bfc30..1a3434f 100644 (file)
@@ -16,6 +16,7 @@
 #include <barrelfish/deferred.h>
 #include <barrelfish/waitset_chan.h>
 #include <stdio.h>
+#include <barrelfish/systime.h>
 
 // FIXME: why do I need quite so many dispatcher headers?
 #include <barrelfish/dispatch.h>
@@ -25,9 +26,6 @@
 
 #include "waitset_chan_priv.h"
 
-// kludge: the kernel currently reports time in ms rather than us
-#define SYSTIME_MULTIPLIER 1000
-
 static void update_wakeup_disabled(dispatcher_handle_t dh)
 {
     struct dispatcher_generic *dg = get_dispatcher_generic(dh);
@@ -36,7 +34,7 @@ static void update_wakeup_disabled(dispatcher_handle_t dh)
     if (dg->deferred_events == NULL) {
         ds->wakeup = 0;
     } else {
-        ds->wakeup = dg->deferred_events->time / SYSTIME_MULTIPLIER;
+        ds->wakeup = dg->deferred_events->time;
     }
 }
 
@@ -45,9 +43,7 @@ static void update_wakeup_disabled(dispatcher_handle_t dh)
  */
 systime_t get_system_time(void)
 {
-    dispatcher_handle_t dh = curdispatcher();
-    struct dispatcher_shared_generic *ds = get_dispatcher_shared_generic(dh);
-    return ds->systime * SYSTIME_MULTIPLIER;
+    return systime_now();
 }
 
 void deferred_event_init(struct deferred_event *event)
@@ -77,9 +73,8 @@ errval_t deferred_event_register(struct deferred_event *event,
     if (err_is_ok(err)) {
         struct dispatcher_generic *dg = get_dispatcher_generic(dh);
 
-        // XXX: determine absolute time for event (ignoring time since dispatch!)
-        event->time = get_system_time() + delay;
-
+        // determine absolute time for event
+        event->time = systime_now() + ns_to_systime((uint64_t)delay * 1000);
         // enqueue in sorted list of pending timers
         for (struct deferred_event *e = dg->deferred_events, *p = NULL; ;
              p = e, e = e->next) {
@@ -179,8 +174,6 @@ static void periodic_event_handler(void *arg)
                            MKCLOSURE(periodic_event_handler, e));
     assert(err_is_ok(err));
 
-    //printf("%s:%s: periodic handler %p\n", disp_name(), __func__, e->cl.handler);
-
     // run handler
     e->cl.handler(e->cl.arg);
 }
@@ -221,8 +214,6 @@ void trigger_deferred_events_disabled(dispatcher_handle_t dh, systime_t now)
     struct deferred_event *e;
     errval_t err;
 
-    now *= SYSTIME_MULTIPLIER;
-
     for (e = dg->deferred_events; e != NULL && e->time <= now; e = e->next) {
         err = waitset_chan_trigger_disabled(&e->waitset_state, dh);
         assert_disabled(err_is_ok(err));
index 0072656..6221a2f 100644 (file)
@@ -26,6 +26,7 @@
 #include <barrelfish/monitor_client.h>
 #include <barrelfish/nameservice_client.h>
 #include <barrelfish/spawn_client.h>
+#include <barrelfish/systime.h>
 #include <barrelfish_kpi/domain_params.h>
 #include <if/monitor_defs.h>
 #include <trace/trace.h>
@@ -365,6 +366,8 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
         }
     }
 
+    dispatcher_handle_t handle = curdispatcher();
+    systime_frequency = get_dispatcher_shared_generic(handle)->systime_frequency;
     return err;
 }
 
diff --git a/lib/barrelfish/systime.c b/lib/barrelfish/systime.c
new file mode 100644 (file)
index 0000000..80d1a3a
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * \file
+ * \brief Systime
+ */
+
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/systime.h>
+
+/// Number of system ticks per one millisecond
+systime_t systime_frequency = 1;
+
+/// Convert nanoseconds to system ticks
+systime_t ns_to_systime(uint64_t nanoseconds)
+{
+    uint64_t q, r;
+
+    q = nanoseconds / 1000000000;
+    r = nanoseconds % 1000000000;
+
+    // Adding half a tick to round properly
+    return q * systime_frequency + (r * systime_frequency + 500000000) / 1000000000;
+}
+
+/// Convert system ticks to nanoseconds
+uint64_t systime_to_ns(systime_t time)
+{
+    systime_t q, r;
+
+    q = time / systime_frequency;
+    r = time % systime_frequency;
+
+    // Adding half a nanosecond to round properly
+    return q * 1000000000 + (r * 1000000000 + systime_frequency / 2) / systime_frequency;
+}