iPXE
timer.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <string.h>
28 #include <ipxe/process.h>
29 #include <ipxe/console.h>
30 #include <ipxe/keys.h>
31 #include <ipxe/nap.h>
32 #include <ipxe/init.h>
33 #include <ipxe/timer.h>
34 
35 /** Current timer */
36 static struct timer *timer;
37 
38 /**
39  * Get current system time in ticks
40  *
41  * @ret ticks Current time, in ticks
42  */
43 unsigned long currticks ( void ) {
44 
45  /* Guard against use during early initialisation */
46  if ( ! timer ) {
47  DBGC ( &timer, "TIMER currticks() called before initialisation "
48  "from %p\n", __builtin_return_address ( 0 ) );
49  return 0;
50  }
51 
52  /* Use selected timer */
53  return timer->currticks();
54 }
55 
56 /**
57  * Delay for a fixed number of microseconds
58  *
59  * @v usecs Number of microseconds for which to delay
60  */
61 void udelay ( unsigned long usecs ) {
62 
63  /* Guard against use during early initialisation */
64  if ( ! timer ) {
65  DBGC ( &timer, "TIMER udelay() called before initialisation "
66  "from %p\n", __builtin_return_address ( 0 ) );
67  return;
68  }
69 
70  /* Use selected timer */
71  timer->udelay ( usecs );
72 }
73 
74 /**
75  * Delay for a fixed number of milliseconds
76  *
77  * @v msecs Number of milliseconds for which to delay
78  */
79 void mdelay ( unsigned long msecs ) {
80 
81  /* Guard against use during early initialisation */
82  if ( ! timer ) {
83  DBGC ( &timer, "TIMER mdelay() called before initialisation "
84  "from %p\n", __builtin_return_address ( 0 ) );
85  return;
86  }
87 
88  /* Delay for specified number of milliseconds */
89  while ( msecs-- )
90  udelay ( 1000 );
91 }
92 
93 /**
94  * Sleep (possibly interruptibly) for a fixed number of seconds
95  *
96  * @v secs Number of seconds for which to delay
97  * @v interrupted Interrupt checking method, or NULL
98  * @ret secs Number of seconds remaining, if interrupted
99  */
100 static unsigned int sleep_interruptible ( unsigned int secs,
101  int ( * interrupted ) ( void ) ) {
102  unsigned long start = currticks();
103  unsigned long now;
104 
105  for ( ; secs ; secs-- ) {
106  while ( ( ( now = currticks() ) - start ) < TICKS_PER_SEC ) {
107  step();
108  if ( interrupted && interrupted() )
109  return secs;
110  cpu_nap();
111  }
112  start = now;
113  }
114 
115  return 0;
116 }
117 
118 /**
119  * Check if sleep has been interrupted by keypress
120  *
121  * @ret interrupted Sleep has been interrupted
122  */
123 static int keypress_interrupted ( void ) {
124 
125  return ( iskey() && ( getchar() == CTRL_C ) );
126 }
127 
128 /**
129  * Sleep (interruptibly) for a fixed number of seconds
130  *
131  * @v secs Number of seconds for which to delay
132  * @ret secs Number of seconds remaining, if interrupted
133  */
134 unsigned int sleep ( unsigned int secs ) {
135 
136  return sleep_interruptible ( secs, keypress_interrupted );
137 }
138 
139 /**
140  * Sleep (uninterruptibly) for a fixed number of seconds
141  *
142  * @v secs Number of seconds for which to delay
143  */
144 void sleep_fixed ( unsigned int secs ) {
145 
146  sleep_interruptible ( secs, NULL );
147 }
148 
149 /**
150  * Find a working timer
151  *
152  */
153 static void timer_probe ( void ) {
154  int rc;
155 
156  /* Use first working timer */
158  if ( ( timer->probe == NULL ) ||
159  ( ( rc = timer->probe() ) == 0 ) ) {
160  DBGC ( &timer, "TIMER using %s\n", timer->name );
161  return;
162  }
163  DBGC ( &timer, "TIMER could not initialise %s: %s\n",
164  timer->name, strerror ( rc ) );
165  }
166 
167  /* This is a fatal error */
168  DBGC ( &timer, "TIMER found no working timers!\n" );
169  while ( 1 ) {}
170 }
171 
172 /** Timer initialisation function */
173 struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = {
174  .name = "timer",
175  .initialise = timer_probe,
176 };
177 
178 /* Drag in timer configuration */
179 REQUIRING_SYMBOL ( timer_init_fn );
180 REQUIRE_OBJECT ( config_timer );
CPU sleeping.
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:16
struct init_fn timer_init_fn __init_fn(INIT_EARLY)
Timer initialisation function.
#define INIT_EARLY
Early initialisation.
Definition: init.h:30
#define DBGC(...)
Definition: compiler.h:505
iPXE timers
FILE_SECBOOT(PERMITTED)
A timer.
Definition: timer.h:29
uint32_t start
Starting offset.
Definition: netvsc.h:12
An initialisation function.
Definition: init.h:15
void(* udelay)(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.h:49
REQUIRE_OBJECT(config_timer)
const char * name
Definition: init.h:16
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.c:61
REQUIRING_SYMBOL(timer_init_fn)
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define CTRL_C
Definition: keys.h:21
unsigned long(* currticks)(void)
Get current system time in ticks.
Definition: timer.h:43
User interaction.
int getchar(void)
Read a single character from any console.
Definition: console.c:86
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
Processes.
int(* probe)(void)
Probe timer.
Definition: timer.h:37
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:79
void cpu_nap(void)
Sleep with interrupts enabled until next CPU interrupt.
const char * name
Name.
Definition: timer.h:31
Key definitions.
static struct timer * timer
Current timer.
Definition: timer.c:36
void step(void)
Single-step a single process.
Definition: process.c:99
void sleep_fixed(unsigned int secs)
Sleep (uninterruptibly) for a fixed number of seconds.
Definition: timer.c:144
static int keypress_interrupted(void)
Check if sleep has been interrupted by keypress.
Definition: timer.c:123
#define TIMERS
Timer table.
Definition: timer.h:53
static void timer_probe(void)
Find a working timer.
Definition: timer.c:153
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:43
static unsigned int sleep_interruptible(unsigned int secs, int(*interrupted)(void))
Sleep (possibly interruptibly) for a fixed number of seconds.
Definition: timer.c:100
unsigned int sleep(unsigned int secs)
Sleep (interruptibly) for a fixed number of seconds.
Definition: timer.c:134
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
int iskey(void)
Check for available input on any console.
Definition: console.c:131