ia64/xen-unstable

view xen/common/keyhandler.c @ 19788:2f9e1348aa98

x86_64: allow more vCPU-s per guest

Since the shared info layout is fixed, guests are required to use
VCPUOP_register_vcpu_info prior to booting any vCPU beyond the
traditional limit of 32.

MAX_VIRT_CPUS, being an implemetation detail of the hypervisor, is no
longer being exposed in the public headers.

The tools changes are clearly incomplete (and done only so things
would
build again), and the current state of the tools (using scalar
variables all over the place to represent vCPU bitmaps) very likely
doesn't permit booting DomU-s with more than the traditional number of
vCPU-s. Testing of the extended functionality was done with Dom0 (96
vCPU-s, as well as 128 vCPU-s out of which the kernel elected - by way
of a simple kernel side patch - to use only some, resulting in a
sparse
bitmap).

ia64 changes only to make things build, and build-tested only (and the
tools part only as far as the build would go without encountering
unrelated problems in the blktap code).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 18 10:14:16 2009 +0100 (2009-06-18)
parents 7dfc0a20fa59
children
line source
1 /******************************************************************************
2 * keyhandler.c
3 */
5 #include <asm/regs.h>
6 #include <xen/keyhandler.h>
7 #include <xen/shutdown.h>
8 #include <xen/event.h>
9 #include <xen/console.h>
10 #include <xen/serial.h>
11 #include <xen/sched.h>
12 #include <xen/softirq.h>
13 #include <xen/domain.h>
14 #include <xen/rangeset.h>
15 #include <xen/compat.h>
16 #include <asm/debugger.h>
17 #include <asm/div64.h>
19 #define KEY_MAX 256
20 #define STR_MAX 64
22 static struct {
23 union {
24 keyhandler_t *handler;
25 irq_keyhandler_t *irq_handler;
26 } u;
27 unsigned int flags;
28 char desc[STR_MAX];
29 } key_table[KEY_MAX];
31 #define KEYHANDLER_IRQ_CALLBACK 0x1
33 static unsigned char keypress_key;
35 static void keypress_action(unsigned long unused)
36 {
37 keyhandler_t *h;
38 unsigned char key = keypress_key;
39 console_start_log_everything();
40 if ( (h = key_table[key].u.handler) != NULL )
41 (*h)(key);
42 console_end_log_everything();
43 }
45 static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
47 void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
48 {
49 irq_keyhandler_t *h;
51 if ( !in_irq() || (key_table[key].flags & KEYHANDLER_IRQ_CALLBACK) )
52 {
53 console_start_log_everything();
54 if ( (h = key_table[key].u.irq_handler) != NULL )
55 (*h)(key, regs);
56 console_end_log_everything();
57 }
58 else
59 {
60 keypress_key = key;
61 tasklet_schedule(&keypress_tasklet);
62 }
63 }
65 void register_keyhandler(
66 unsigned char key, keyhandler_t *handler, char *desc)
67 {
68 ASSERT(key_table[key].u.handler == NULL);
69 key_table[key].u.handler = handler;
70 key_table[key].flags = 0;
71 safe_strcpy(key_table[key].desc, desc);
72 }
74 void register_irq_keyhandler(
75 unsigned char key, irq_keyhandler_t *handler, char *desc)
76 {
77 ASSERT(key_table[key].u.irq_handler == NULL);
78 key_table[key].u.irq_handler = handler;
79 key_table[key].flags = KEYHANDLER_IRQ_CALLBACK;
80 safe_strcpy(key_table[key].desc, desc);
81 }
83 static void show_handlers(unsigned char key)
84 {
85 int i;
86 printk("'%c' pressed -> showing installed handlers\n", key);
87 for ( i = 0; i < KEY_MAX; i++ )
88 if ( key_table[i].u.handler != NULL )
89 printk(" key '%c' (ascii '%02x') => %s\n",
90 (i<33 || i>126)?(' '):(i),i,
91 key_table[i].desc);
92 }
94 static void __dump_execstate(void *unused)
95 {
96 dump_execution_state();
97 printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
98 if ( is_idle_vcpu(current) )
99 printk("No guest context (CPU is idle).\n");
100 else
101 show_execution_state(guest_cpu_user_regs());
102 }
104 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
105 {
106 unsigned int cpu;
108 /* We want to get everything out that we possibly can. */
109 console_start_sync();
111 printk("'%c' pressed -> dumping registers\n", key);
113 /* Get local execution state out immediately, in case we get stuck. */
114 printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
115 __dump_execstate(NULL);
117 for_each_online_cpu ( cpu )
118 {
119 if ( cpu == smp_processor_id() )
120 continue;
121 printk("\n*** Dumping CPU%d host state: ***\n", cpu);
122 on_selected_cpus(cpumask_of(cpu), __dump_execstate, NULL, 1);
123 }
125 printk("\n");
127 console_end_sync();
128 }
130 static void dump_dom0_registers(unsigned char key)
131 {
132 struct vcpu *v;
134 if ( dom0 == NULL )
135 return;
137 printk("'%c' pressed -> dumping Dom0's registers\n", key);
139 for_each_vcpu ( dom0, v )
140 vcpu_show_execution_state(v);
141 }
143 static void halt_machine(unsigned char key, struct cpu_user_regs *regs)
144 {
145 printk("'%c' pressed -> rebooting machine\n", key);
146 machine_restart(0);
147 }
149 static void cpuset_print(char *set, int size, cpumask_t mask)
150 {
151 *set++ = '{';
152 set += cpulist_scnprintf(set, size-2, mask);
153 *set++ = '}';
154 *set++ = '\0';
155 }
157 static void periodic_timer_print(char *str, int size, uint64_t period)
158 {
159 if ( period == 0 )
160 {
161 strlcpy(str, "No periodic timer", size);
162 return;
163 }
165 snprintf(str, size,
166 "%u Hz periodic timer (period %u ms)",
167 1000000000/(int)period, (int)period/1000000);
168 }
170 static void dump_domains(unsigned char key)
171 {
172 struct domain *d;
173 struct vcpu *v;
174 s_time_t now = NOW();
175 char tmpstr[100];
177 printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
178 (u32)(now>>32), (u32)now);
180 rcu_read_lock(&domlist_read_lock);
182 for_each_domain ( d )
183 {
184 printk("General information for domain %u:\n", d->domain_id);
185 cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
186 printk(" refcnt=%d dying=%d nr_pages=%d xenheap_pages=%d "
187 "dirty_cpus=%s max_pages=%u\n",
188 atomic_read(&d->refcnt), d->is_dying,
189 d->tot_pages, d->xenheap_pages, tmpstr, d->max_pages);
190 printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
191 "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
192 d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
193 d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
194 d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
195 d->handle[12], d->handle[13], d->handle[14], d->handle[15],
196 d->vm_assist);
198 arch_dump_domain_info(d);
200 rangeset_domain_printk(d);
202 dump_pageframe_info(d);
204 printk("VCPU information and callbacks for domain %u:\n",
205 d->domain_id);
206 for_each_vcpu ( d, v ) {
207 printk(" VCPU%d: CPU%d [has=%c] flags=%lx poll=%d "
208 "upcall_pend = %02x, upcall_mask = %02x ",
209 v->vcpu_id, v->processor,
210 v->is_running ? 'T':'F',
211 v->pause_flags, v->poll_evtchn,
212 v->vcpu_info ? vcpu_info(v, evtchn_upcall_pending) : 0,
213 v->vcpu_info ? vcpu_info(v, evtchn_upcall_mask) : 1);
214 cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
215 printk("dirty_cpus=%s ", tmpstr);
216 cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
217 printk("cpu_affinity=%s\n", tmpstr);
218 arch_dump_vcpu_info(v);
219 periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
220 printk(" %s\n", tmpstr);
221 if ( !v->vcpu_info )
222 continue;
223 printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
224 VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
225 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
226 &shared_info(d, evtchn_pending)),
227 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
228 &shared_info(d, evtchn_mask)),
229 test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
230 BITS_PER_EVTCHN_WORD(d),
231 &vcpu_info(v, evtchn_pending_sel)));
232 send_guest_vcpu_virq(v, VIRQ_DEBUG);
233 }
234 }
236 rcu_read_unlock(&domlist_read_lock);
237 }
239 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
240 static s_time_t read_clocks_time[NR_CPUS];
241 static u64 read_cycles_time[NR_CPUS];
243 static void read_clocks_slave(void *unused)
244 {
245 unsigned int cpu = smp_processor_id();
246 local_irq_disable();
247 while ( !cpu_isset(cpu, read_clocks_cpumask) )
248 cpu_relax();
249 read_clocks_time[cpu] = NOW();
250 read_cycles_time[cpu] = get_cycles();
251 cpu_clear(cpu, read_clocks_cpumask);
252 local_irq_enable();
253 }
255 static void read_clocks(unsigned char key)
256 {
257 unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
258 unsigned int min_cycles_cpu, max_cycles_cpu;
259 u64 min_stime, max_stime, dif_stime;
260 u64 min_cycles, max_cycles, dif_cycles;
261 static u64 sumdif_stime = 0, maxdif_stime = 0;
262 static u64 sumdif_cycles = 0, maxdif_cycles = 0;
263 static u32 count = 0;
264 static DEFINE_SPINLOCK(lock);
266 spin_lock(&lock);
268 smp_call_function(read_clocks_slave, NULL, 0);
270 local_irq_disable();
271 read_clocks_cpumask = cpu_online_map;
272 read_clocks_time[cpu] = NOW();
273 read_cycles_time[cpu] = get_cycles();
274 cpu_clear(cpu, read_clocks_cpumask);
275 local_irq_enable();
277 while ( !cpus_empty(read_clocks_cpumask) )
278 cpu_relax();
280 min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
281 for_each_online_cpu ( cpu )
282 {
283 if ( read_clocks_time[cpu] < read_clocks_time[min_stime_cpu] )
284 min_stime_cpu = cpu;
285 if ( read_clocks_time[cpu] > read_clocks_time[max_stime_cpu] )
286 max_stime_cpu = cpu;
287 if ( read_cycles_time[cpu] < read_cycles_time[min_cycles_cpu] )
288 min_cycles_cpu = cpu;
289 if ( read_cycles_time[cpu] > read_cycles_time[max_cycles_cpu] )
290 max_cycles_cpu = cpu;
291 }
293 min_stime = read_clocks_time[min_stime_cpu];
294 max_stime = read_clocks_time[max_stime_cpu];
295 min_cycles = read_cycles_time[min_cycles_cpu];
296 max_cycles = read_cycles_time[max_cycles_cpu];
298 spin_unlock(&lock);
300 dif_stime = max_stime - min_stime;
301 if ( dif_stime > maxdif_stime )
302 maxdif_stime = dif_stime;
303 sumdif_stime += dif_stime;
304 dif_cycles = max_cycles - min_cycles;
305 if ( dif_cycles > maxdif_cycles )
306 maxdif_cycles = dif_cycles;
307 sumdif_cycles += dif_cycles;
308 count++;
309 printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
310 "samples=%"PRIu32" current=%"PRIu64"ns\n",
311 maxdif_stime, sumdif_stime/count, count, dif_stime);
312 printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
313 "samples=%"PRIu32" current=%"PRIu64"\n",
314 maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
315 }
317 extern void dump_runq(unsigned char key);
319 #ifdef PERF_COUNTERS
320 extern void perfc_printall(unsigned char key);
321 extern void perfc_reset(unsigned char key);
322 #endif
324 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
325 {
326 printk("'%c' pressed -> trapping into debugger\n", key);
327 (void)debugger_trap_fatal(0xf001, regs);
328 nop(); /* Prevent the compiler doing tail call
329 optimisation, as that confuses xendbg a
330 bit. */
331 }
333 void __init initialize_keytable(void)
334 {
335 register_irq_keyhandler(
336 'd', dump_registers, "dump registers");
337 register_keyhandler(
338 'h', show_handlers, "show this message");
339 register_keyhandler(
340 'q', dump_domains, "dump domain (and guest debug) info");
341 register_keyhandler(
342 'r', dump_runq, "dump run queues");
343 register_irq_keyhandler(
344 'R', halt_machine, "reboot machine");
346 register_keyhandler(
347 't', read_clocks, "display multi-cpu clock info");
349 #ifdef PERF_COUNTERS
350 register_keyhandler(
351 'p', perfc_printall, "print performance counters");
352 register_keyhandler(
353 'P', perfc_reset, "reset performance counters");
354 #endif
356 register_keyhandler(
357 '0', dump_dom0_registers, "dump Dom0 registers");
359 register_irq_keyhandler('%', do_debug_key, "Trap to xendbg");
360 }
362 /*
363 * Local variables:
364 * mode: C
365 * c-set-style: "BSD"
366 * c-basic-offset: 4
367 * tab-width: 4
368 * indent-tabs-mode: nil
369 * End:
370 */