~ubuntu-branches/ubuntu/trusty/grub2/trusty

« back to all changes in this revision

Viewing changes to grub-core/kern/i386/tsc.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-01-16 15:18:04 UTC
  • mfrom: (17.6.38 experimental)
  • Revision ID: package-import@ubuntu.com-20140116151804-3foouk7fpqcq3sxx
Tags: 2.02~beta2-2
* Convert patch handling to git-dpm.
* Add bi-endian support to ELF parser (Tomohiro B Berry).
* Adjust restore_mkdevicemap.patch to mark get_kfreebsd_version as static,
  to appease "gcc -Werror=missing-prototypes".
* Cherry-pick from upstream:
  - Change grub-macbless' manual page section to 8.
* Install grub-glue-efi, grub-macbless, grub-render-label, and
  grub-syslinux2cfg.
* grub-shell: Pass -no-pad to xorriso when building floppy images.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
#include <grub/time.h>
25
25
#include <grub/misc.h>
26
26
#include <grub/i386/tsc.h>
 
27
#include <grub/i386/cpuid.h>
 
28
#ifdef GRUB_MACHINE_XEN
 
29
#include <grub/xen.h>
 
30
#else
27
31
#include <grub/i386/pit.h>
 
32
#endif
 
33
#include <grub/cpu/io.h>
28
34
 
29
35
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
30
36
static grub_uint64_t tsc_boot_time;
31
37
 
32
 
/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
33
 
static grub_uint64_t tsc_ticks_per_ms;
34
 
 
35
 
 
36
 
grub_uint64_t
 
38
/* Calibrated TSC rate.  (In ms per 2^32 ticks) */
 
39
/* We assume that the tick is less than 1 ms and hence this value fits
 
40
   in 32-bit.  */
 
41
grub_uint32_t grub_tsc_rate;
 
42
 
 
43
/* Read the TSC value, which increments with each CPU clock cycle. */
 
44
static __inline grub_uint64_t
 
45
grub_get_tsc (void)
 
46
{
 
47
  grub_uint32_t lo, hi;
 
48
  grub_uint32_t a,b,c,d;
 
49
 
 
50
  /* The CPUID instruction is a 'serializing' instruction, and
 
51
     avoids out-of-order execution of the RDTSC instruction. */
 
52
  grub_cpuid (0,a,b,c,d);
 
53
  /* Read TSC value.  We cannot use "=A", since this would use
 
54
     %rax on x86_64. */
 
55
  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
 
56
 
 
57
  return (((grub_uint64_t) hi) << 32) | lo;
 
58
}
 
59
 
 
60
static __inline int
 
61
grub_cpu_is_tsc_supported (void)
 
62
{
 
63
  grub_uint32_t a,b,c,d;
 
64
  if (! grub_cpu_is_cpuid_supported ())
 
65
    return 0;
 
66
 
 
67
  grub_cpuid(1,a,b,c,d);
 
68
 
 
69
  return (d & (1 << 4)) != 0;
 
70
}
 
71
 
 
72
#ifndef GRUB_MACHINE_XEN
 
73
 
 
74
static void
 
75
grub_pit_wait (grub_uint16_t tics)
 
76
{
 
77
  /* Disable timer2 gate and speaker.  */
 
78
  grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
 
79
             & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
 
80
             GRUB_PIT_SPEAKER_PORT);
 
81
 
 
82
  /* Set tics.  */
 
83
  grub_outb (GRUB_PIT_CTRL_SELECT_2 | GRUB_PIT_CTRL_READLOAD_WORD,
 
84
             GRUB_PIT_CTRL);
 
85
  grub_outb (tics & 0xff, GRUB_PIT_COUNTER_2);
 
86
  grub_outb (tics >> 8, GRUB_PIT_COUNTER_2);
 
87
 
 
88
  /* Enable timer2 gate, keep speaker disabled.  */
 
89
  grub_outb ((grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ GRUB_PIT_SPK_DATA)
 
90
             | GRUB_PIT_SPK_TMR2,
 
91
             GRUB_PIT_SPEAKER_PORT);
 
92
 
 
93
  /* Wait.  */
 
94
  while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
 
95
 
 
96
  /* Disable timer2 gate and speaker.  */
 
97
  grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
 
98
             & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
 
99
             GRUB_PIT_SPEAKER_PORT);
 
100
}
 
101
#endif
 
102
 
 
103
static grub_uint64_t
37
104
grub_tsc_get_time_ms (void)
38
105
{
39
 
  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
 
106
  grub_uint64_t a = grub_get_tsc () - tsc_boot_time;
 
107
  grub_uint64_t ah = a >> 32;
 
108
  grub_uint64_t al = a & 0xffffffff;
 
109
 
 
110
  return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
40
111
}
41
112
 
42
 
 
43
 
/* How many RTC ticks to use for calibration loop. (>= 1) */
44
 
#define CALIBRATION_TICKS 2
45
 
 
 
113
#ifndef GRUB_MACHINE_XEN
46
114
/* Calibrate the TSC based on the RTC.  */
47
115
static void
48
116
calibrate_tsc (void)
49
117
{
50
118
  /* First calibrate the TSC rate (relative, not absolute time). */
51
 
  grub_uint64_t start_tsc;
52
119
  grub_uint64_t end_tsc;
53
120
 
54
 
  start_tsc = grub_get_tsc ();
 
121
  tsc_boot_time = grub_get_tsc ();
55
122
  grub_pit_wait (0xffff);
56
123
  end_tsc = grub_get_tsc ();
57
124
 
58
 
  tsc_ticks_per_ms = grub_divmod64 (end_tsc - start_tsc, 55, 0);
 
125
  grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
59
126
}
 
127
#endif
60
128
 
61
129
void
62
130
grub_tsc_init (void)
63
131
{
 
132
#ifdef GRUB_MACHINE_XEN
 
133
  grub_uint64_t t;
 
134
  tsc_boot_time = grub_get_tsc ();
 
135
  t = grub_xen_shared_info->vcpu_info[0].time.tsc_to_system_mul;
 
136
  if (grub_xen_shared_info->vcpu_info[0].time.tsc_shift > 0)
 
137
    t <<= grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
 
138
  else
 
139
    t >>= -grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
 
140
  grub_tsc_rate = grub_divmod64 (t, 1000000, 0);
 
141
  grub_install_get_time_ms (grub_tsc_get_time_ms);
 
142
#else
64
143
  if (grub_cpu_is_tsc_supported ())
65
144
    {
66
 
      tsc_boot_time = grub_get_tsc ();
67
145
      calibrate_tsc ();
68
146
      grub_install_get_time_ms (grub_tsc_get_time_ms);
69
147
    }
75
153
      grub_fatal ("no TSC found");
76
154
#endif
77
155
    }
 
156
#endif
78
157
}