source: trunk/packages/xen-3.1/xen-3.1/xen/common/keyhandler.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 9.2 KB
Line 
1/******************************************************************************
2 * keyhandler.c
3 */
4
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/shadow.h>
18#include <asm/div64.h>
19
20#define KEY_MAX 256
21#define STR_MAX  64
22
23static struct {
24    union {
25        keyhandler_t     *handler;
26        irq_keyhandler_t *irq_handler;
27    } u;
28    unsigned int flags;
29    char         desc[STR_MAX];
30} key_table[KEY_MAX];
31
32#define KEYHANDLER_IRQ_CALLBACK 0x1
33
34static unsigned char keypress_key;
35
36static void keypress_softirq(void)
37{
38    keyhandler_t *h;
39    unsigned char key = keypress_key;
40    console_start_log_everything();
41    if ( (h = key_table[key].u.handler) != NULL )
42        (*h)(key);
43    console_end_log_everything();
44}
45
46void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
47{
48    irq_keyhandler_t *h;
49
50    if ( !in_irq() || (key_table[key].flags & KEYHANDLER_IRQ_CALLBACK) )
51    {
52        console_start_log_everything();
53        if ( (h = key_table[key].u.irq_handler) != NULL )
54            (*h)(key, regs);
55        console_end_log_everything();
56    }
57    else
58    {
59        keypress_key = key;
60        raise_softirq(KEYPRESS_SOFTIRQ);
61    }
62}
63
64void register_keyhandler(
65    unsigned char key, keyhandler_t *handler, char *desc)
66{
67    ASSERT(key_table[key].u.handler == NULL);
68    key_table[key].u.handler = handler;
69    key_table[key].flags     = 0;
70    safe_strcpy(key_table[key].desc, desc);
71}
72
73void register_irq_keyhandler(
74    unsigned char key, irq_keyhandler_t *handler, char *desc)
75{
76    ASSERT(key_table[key].u.irq_handler == NULL);
77    key_table[key].u.irq_handler = handler;
78    key_table[key].flags         = KEYHANDLER_IRQ_CALLBACK;
79    safe_strcpy(key_table[key].desc, desc);
80}
81
82static void show_handlers(unsigned char key)
83{
84    int i;
85    printk("'%c' pressed -> showing installed handlers\n", key);
86    for ( i = 0; i < KEY_MAX; i++ ) 
87        if ( key_table[i].u.handler != NULL ) 
88            printk(" key '%c' (ascii '%02x') => %s\n", 
89                   (i<33 || i>126)?(' '):(i),i,
90                   key_table[i].desc);
91}
92
93static void __dump_execstate(void *unused)
94{
95    dump_execution_state();
96    printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
97    if ( is_idle_vcpu(current) )
98        printk("No guest context (CPU is idle).\n");
99    else
100        show_execution_state(guest_cpu_user_regs());
101}
102
103static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
104{
105    unsigned int cpu;
106
107    printk("'%c' pressed -> dumping registers\n", key);
108
109    /* Get local execution state out immediately, in case we get stuck. */
110    printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
111    __dump_execstate(NULL);
112
113    for_each_online_cpu ( cpu )
114    {
115        if ( cpu == smp_processor_id() )
116            continue;
117        printk("\n*** Dumping CPU%d host state: ***\n", cpu);
118        on_selected_cpus(cpumask_of_cpu(cpu), __dump_execstate, NULL, 1, 1);
119    }
120
121    printk("\n");
122}
123
124static void halt_machine(unsigned char key, struct cpu_user_regs *regs)
125{
126    printk("'%c' pressed -> rebooting machine\n", key);
127    machine_restart(NULL);
128}
129
130static void cpuset_print(char *set, int size, cpumask_t mask)
131{
132    *set++ = '{';
133    set += cpulist_scnprintf(set, size-2, mask);
134    *set++ = '}';
135    *set++ = '\0';
136}
137
138static void periodic_timer_print(char *str, int size, uint64_t period)
139{
140    if ( period == 0 )
141    {
142        strlcpy(str, "No periodic timer", size);
143        return;
144    }
145
146    snprintf(str, size,
147             "%u Hz periodic timer (period %u ms)",
148             1000000000/(int)period, (int)period/1000000);
149}
150
151static void dump_domains(unsigned char key)
152{
153    struct domain *d;
154    struct vcpu   *v;
155    s_time_t       now = NOW();
156    char           tmpstr[100];
157
158    printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
159           (u32)(now>>32), (u32)now);
160
161    rcu_read_lock(&domlist_read_lock);
162
163    for_each_domain ( d )
164    {
165        printk("General information for domain %u:\n", d->domain_id);
166        cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
167        printk("    refcnt=%d nr_pages=%d xenheap_pages=%d "
168               "dirty_cpus=%s\n",
169               atomic_read(&d->refcnt),
170               d->tot_pages, d->xenheap_pages, tmpstr);
171        printk("    handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
172               "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
173               d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
174               d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
175               d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
176               d->handle[12], d->handle[13], d->handle[14], d->handle[15],
177               d->vm_assist);
178
179        arch_dump_domain_info(d);
180
181        rangeset_domain_printk(d);
182
183        dump_pageframe_info(d);
184               
185        printk("VCPU information and callbacks for domain %u:\n",
186               d->domain_id);
187        for_each_vcpu ( d, v ) {
188            printk("    VCPU%d: CPU%d [has=%c] flags=%lx "
189                   "upcall_pend = %02x, upcall_mask = %02x ",
190                   v->vcpu_id, v->processor,
191                   v->is_running ? 'T':'F',
192                   v->pause_flags,
193                   vcpu_info(v, evtchn_upcall_pending),
194                   vcpu_info(v, evtchn_upcall_mask));
195            cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
196            printk("dirty_cpus=%s ", tmpstr);
197            cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
198            printk("cpu_affinity=%s\n", tmpstr);
199            arch_dump_vcpu_info(v);
200            periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
201            printk("    %s\n", tmpstr);
202            printk("    Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
203                   VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
204                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG], 
205                            shared_info_addr(d, evtchn_pending)),
206                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG], 
207                            shared_info_addr(d, evtchn_mask)),
208                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
209                            BITS_PER_GUEST_LONG(d),
210                            vcpu_info_addr(v, evtchn_pending_sel)));
211            send_guest_vcpu_virq(v, VIRQ_DEBUG);
212        }
213    }
214
215    rcu_read_unlock(&domlist_read_lock);
216}
217
218static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
219static s_time_t read_clocks_time[NR_CPUS];
220
221static void read_clocks_slave(void *unused)
222{
223    unsigned int cpu = smp_processor_id();
224    while ( !cpu_isset(cpu, read_clocks_cpumask) )
225        cpu_relax();
226    read_clocks_time[cpu] = NOW();
227    cpu_clear(cpu, read_clocks_cpumask);
228}
229
230static void read_clocks(unsigned char key)
231{
232    unsigned int cpu = smp_processor_id(), min_cpu, max_cpu;
233    u64 min, max, dif, difus;
234    static DEFINE_SPINLOCK(lock);
235
236    spin_lock(&lock);
237
238    smp_call_function(read_clocks_slave, NULL, 0, 0);
239
240    local_irq_disable();
241    read_clocks_cpumask = cpu_online_map;
242    read_clocks_time[cpu] = NOW();
243    cpu_clear(cpu, read_clocks_cpumask);
244    local_irq_enable();
245
246    while ( !cpus_empty(read_clocks_cpumask) )
247        cpu_relax();
248
249    min_cpu = max_cpu = cpu;
250    for_each_online_cpu ( cpu )
251    {
252        if ( read_clocks_time[cpu] < read_clocks_time[min_cpu] )
253            min_cpu = cpu;
254        if ( read_clocks_time[cpu] > read_clocks_time[max_cpu] )
255            max_cpu = cpu;
256    }
257
258    min = read_clocks_time[min_cpu];
259    max = read_clocks_time[max_cpu];
260
261    spin_unlock(&lock);
262
263    dif = difus = max - min;
264    do_div(difus, 1000);
265    printk("Min = %"PRIu64" ; Max = %"PRIu64" ; Diff = %"PRIu64
266           " (%"PRIu64" microseconds)\n",
267           min, max, dif, difus);
268}
269
270extern void dump_runq(unsigned char key);
271
272#ifdef PERF_COUNTERS
273extern void perfc_printall(unsigned char key);
274extern void perfc_reset(unsigned char key);
275#endif
276
277static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
278{
279    (void)debugger_trap_fatal(0xf001, regs);
280    nop(); /* Prevent the compiler doing tail call
281                             optimisation, as that confuses xendbg a
282                             bit. */
283}
284
285void initialize_keytable(void)
286{
287    open_softirq(KEYPRESS_SOFTIRQ, keypress_softirq);
288
289    register_irq_keyhandler(
290        'd', dump_registers, "dump registers");
291    register_keyhandler(
292        'h', show_handlers, "show this message");
293    register_keyhandler(
294        'q', dump_domains, "dump domain (and guest debug) info");
295    register_keyhandler(
296        'r', dump_runq,      "dump run queues");
297    register_irq_keyhandler(
298        'R', halt_machine,   "reboot machine");
299
300    register_keyhandler(
301        't', read_clocks, "display multi-cpu clock info");
302
303#ifdef PERF_COUNTERS
304    register_keyhandler(
305        'p', perfc_printall, "print performance counters");
306    register_keyhandler(
307        'P', perfc_reset,    "reset performance counters");
308#endif
309
310    register_irq_keyhandler('%', do_debug_key,   "Trap to xendbg");
311}
312
313/*
314 * Local variables:
315 * mode: C
316 * c-set-style: "BSD"
317 * c-basic-offset: 4
318 * tab-width: 4
319 * indent-tabs-mode: nil
320 * End:
321 */
Note: See TracBrowser for help on using the repository browser.