Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


fixes for single core guest on multicore capable systeM
[palacios.git] / palacios / src / devices / 8254.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_dev_mgr.h>
23 #include <palacios/vmm_time.h>
24 #include <palacios/vmm_util.h>
25 #include <palacios/vmm_intr.h>
26 #include <palacios/vmm_config.h>
27
28
29 #ifndef CONFIG_DEBUG_PIT
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35
36 // constants
37 #define OSC_HZ 1193182
38
39
40 /* The 8254 has three counters and one control port */
41 #define CHANNEL0_PORT 0x40
42 #define CHANNEL1_PORT 0x41
43 #define CHANNEL2_PORT 0x42
44 #define COMMAND_PORT 0x43
45
46
47 #define PIT_INTR_NUM 0
48
49 /* The order of these typedefs is important because the numerical values correspond to the 
50  * values coming from the io ports
51  */
52 typedef enum {NOT_RUNNING, PENDING, RUNNING} channel_run_state_t;
53 typedef enum {NOT_WAITING, WAITING_LOBYTE, WAITING_HIBYTE} channel_access_state_t;
54 typedef enum {LATCH_COUNT, LOBYTE_ONLY, HIBYTE_ONLY, LOBYTE_HIBYTE} channel_access_mode_t;
55 typedef enum {IRQ_ON_TERM_CNT, ONE_SHOT, RATE_GEN, SQR_WAVE, SW_STROBE, HW_STROBE} channel_op_mode_t;
56
57
58 struct channel {
59     channel_access_mode_t access_mode;
60     channel_access_state_t access_state;
61     channel_run_state_t run_state;
62
63     channel_op_mode_t op_mode;
64
65
66     // Time til interrupt trigger 
67
68     ushort_t counter;
69     ushort_t reload_value;
70
71     ushort_t latched_value;
72   
73     enum {NOTLATCHED, LATCHED} latch_state;
74
75     enum {LSB, MSB} read_state;
76
77     uint_t output_pin : 1;
78     uint_t gate_input_pin : 1;
79 };
80
81
82 struct pit {
83
84     ullong_t pit_counter;
85     ullong_t pit_reload;
86
87
88     struct channel ch_0;
89     struct channel ch_1;
90     struct channel ch_2;
91 };
92
93
94 struct pit_cmd_word {
95     uint_t bcd_mode    : 1;
96     uint_t op_mode     : 3;
97     uint_t access_mode : 2;
98     uint_t channel     : 2;
99 };
100
101 struct pit_rdb_cmd_word {
102     uint_t rsvd         : 1; // SBZ
103     uint_t ch_0         : 1;
104     uint_t ch_1         : 1;
105     uint_t ch_2         : 1;
106     uint_t latch_status : 1;
107     uint_t latch_count  : 1;
108     uint_t readback_cmd : 2; // Must Be 0x3
109 };
110
111 struct pit_rdb_status_word {
112     uint_t bcd_mode     : 1;
113     uint_t op_mode      : 3;
114     uint_t access_mode  : 2;
115     uint_t null_count   : 1;
116     uint_t pin_state    : 1; 
117 };
118
119
120
121 /* 
122  * This should call out to handle_SQR_WAVE_tics, etc... 
123  */
124 // Returns true if the the output signal changed state
125 static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint_t oscillations) {
126     uint_t channel_cycles = 0;
127     uint_t output_changed = 0;
128   
129     // PrintDebug("8254 PIT: %d crystal tics\n", oscillations);
130     if (ch->run_state == PENDING) {
131         oscillations--;
132         ch->counter = ch->reload_value;
133
134         if (ch->op_mode == SQR_WAVE) {
135             ch->counter -= ch->counter % 2;
136         }
137
138         ch->run_state = RUNNING;
139     } else if (ch->run_state != RUNNING) {
140         return output_changed;
141     }
142
143     /*
144       PrintDebug("8254 PIT: Channel Run State = %d, counter=", ch->run_state);
145       PrintTraceLL(ch->counter);
146       PrintDebug("\n");
147     */
148     if (ch->op_mode == SQR_WAVE) {
149         oscillations *= 2;
150     }
151
152     if (ch->counter > oscillations) {
153         ch->counter -= oscillations;
154         return output_changed;
155     } else {
156         ushort_t reload_val = ch->reload_value; 
157
158         if (ch->op_mode == SW_STROBE) {
159             reload_val = 0xffff;
160         }
161
162         // TODO: Check this....
163         // Is this correct???
164         if (reload_val == 0) {
165             reload_val = 1;
166         }
167
168         oscillations -= ch->counter;
169         ch->counter = 0;
170         channel_cycles = 1;
171
172         if (ch->op_mode == SQR_WAVE) {
173             reload_val -= reload_val % 2;
174         }
175
176         channel_cycles += oscillations / reload_val;
177         oscillations = oscillations % reload_val;
178
179         ch->counter = reload_val - oscillations;
180     }
181
182     //  PrintDebug("8254 PIT: Channel Cycles: %d\n", channel_cycles);
183   
184
185
186     switch (ch->op_mode) {
187         case IRQ_ON_TERM_CNT:
188             if ((channel_cycles > 0) && (ch->output_pin == 0)) {
189                 ch->output_pin = 1; 
190                 output_changed = 1;
191             }
192             break;
193         case ONE_SHOT:
194             if ((channel_cycles > 0) && (ch->output_pin == 0)) {
195                 ch->output_pin = 1; 
196                 output_changed = 1;
197             }
198             break;
199         case RATE_GEN:
200             // See the data sheet: we ignore the output pin cycle...
201             if (channel_cycles > 0) {
202                 output_changed = 1;
203             }
204             break;
205         case SQR_WAVE:
206             ch->output_pin = (ch->output_pin + 1) % 2;
207
208             if (ch->output_pin == 1) {
209                 output_changed = 1;
210             }
211
212             break;
213         case SW_STROBE:
214
215             if (channel_cycles > 0) {
216                 if (ch->output_pin == 1) {
217                     ch->output_pin = 0;
218                     output_changed = 1;
219                 }
220             }
221             break;
222         case HW_STROBE:
223             PrintError("Hardware strobe not implemented\n");
224             return -1;
225             break;
226         default:
227             break;
228     }
229
230     return output_changed;
231 }
232                                 
233
234 #include <palacios/vm_guest.h>
235
236 static void pit_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
237     struct vm_device * dev = (struct vm_device *)private_data;
238     struct pit * state = (struct pit *)dev->private_data;
239     //  ullong_t tmp_ctr = state->pit_counter;
240     ullong_t tmp_cycles;
241     uint_t oscillations = 0;
242
243
244     /*
245       PrintDebug("updating cpu_cycles=");
246       PrintTraceLL(cpu_cycles);
247       PrintDebug("\n");
248     
249       PrintDebug("pit_counter=");
250       PrintTraceLL(state->pit_counter);
251       PrintDebug("\n");
252     
253       PrintDebug("pit_reload=");
254       PrintTraceLL(state->pit_reload);
255       PrintDebug("\n");
256     */
257
258     if (state->pit_counter > cpu_cycles) {
259         // Easy...
260         state->pit_counter -= cpu_cycles;
261     } else {
262         ushort_t reload_val = state->pit_reload;
263         // Take off the first part
264         cpu_cycles -= state->pit_counter;
265         state->pit_counter = 0;
266         oscillations = 1;
267     
268         if (cpu_cycles > state->pit_reload) {
269             // how many full oscillations
270       
271             //PrintError("cpu_cycles = %p, reload = %p...\n", 
272             //   (void *)(addr_t)cpu_cycles, 
273             //   (void *)(addr_t)state->pit_reload);
274
275             // How do we check for a one shot....
276             if (state->pit_reload == 0) {
277                 reload_val = 1;
278             }
279
280             tmp_cycles = cpu_cycles;
281
282       
283 #ifdef __V3_64BIT__
284             cpu_cycles = tmp_cycles % state->pit_reload;
285             tmp_cycles = tmp_cycles / state->pit_reload;
286 #else
287             cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
288 #endif
289         
290             oscillations += tmp_cycles;
291         }
292
293         // update counter with remainder (mod reload)
294         state->pit_counter = state->pit_reload - cpu_cycles;    
295
296         //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
297         if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
298             // raise interrupt
299             PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
300             v3_raise_irq(info->vm_info, 0);
301         }
302
303         //handle_crystal_tics(dev, &(state->ch_1), oscillations);
304         //handle_crystal_tics(dev, &(state->ch_2), oscillations);
305     }
306   
307
308
309  
310     return;
311 }
312
313
314 static void pit_advance_time(struct guest_info * core, void * private_data) {
315
316     v3_raise_irq(core->vm_info, 0);
317 }
318
319
320
321 /* This should call out to handle_SQR_WAVE_write, etc...
322  */
323 static int handle_channel_write(struct channel * ch, char val) {
324
325     switch (ch->access_state) {      
326         case WAITING_HIBYTE:
327             {
328                 ushort_t tmp_val = ((ushort_t)val) << 8;
329                 ch->reload_value &= 0x00ff;
330                 ch->reload_value |= tmp_val;
331         
332
333                 if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)){
334                     ch->run_state = PENDING;  
335                 }
336         
337                 if (ch->access_mode == LOBYTE_HIBYTE) {
338                     ch->access_state = WAITING_LOBYTE;
339                 }
340
341                 PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);        
342                 PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
343                 break;
344             }
345         case WAITING_LOBYTE:
346             ch->reload_value &= 0xff00;
347             ch->reload_value |= val;
348       
349             if (ch->access_mode == LOBYTE_HIBYTE) {
350                 ch->access_state = WAITING_HIBYTE;
351             } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
352                 ch->run_state = PENDING;
353             }
354       
355             PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);
356             PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
357             break;
358         default:
359             PrintError("Invalid Access state\n");
360             return -1;
361     }
362     
363
364     switch (ch->op_mode) {
365         case IRQ_ON_TERM_CNT:
366             ch->output_pin = 0;
367             break;
368         case ONE_SHOT:
369             ch->output_pin = 1;
370             break;
371         case RATE_GEN:
372             ch->output_pin = 1;
373             break;
374         case SQR_WAVE:
375             ch->output_pin = 1;
376             break;
377         case SW_STROBE:
378             ch->output_pin = 1;
379             break;
380         default:
381             PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
382             return -1;
383             break;
384     }
385
386
387     return 0;
388 }
389
390
391 static int handle_channel_read(struct channel * ch, char * val) {
392
393     ushort_t * myval;
394
395     if (ch->latch_state == NOTLATCHED) { 
396         myval = &(ch->counter);
397     } else {
398         myval = &(ch->latched_value);
399     }
400
401     if (ch->read_state == LSB) { 
402         *val = ((char*)myval)[0];  // little endian
403         ch->read_state = MSB;
404     } else {
405         *val = ((char*)myval)[1];
406         ch->read_state = LSB;
407         if (ch->latch_state == LATCHED) { 
408             ch->latch_state = NOTLATCHED;
409         }
410     }
411
412     return 0;
413
414 }
415
416
417
418
419
420 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
421     ch->op_mode = cmd.op_mode;
422     ch->access_mode = cmd.access_mode;
423
424
425
426
427     switch (cmd.access_mode) {
428         case LATCH_COUNT:
429             if (ch->latch_state == NOTLATCHED) { 
430                 ch->latched_value = ch->counter;
431                 ch->latch_state = LATCHED;
432             }
433             break;
434         case HIBYTE_ONLY:
435             ch->access_state = WAITING_HIBYTE;
436             break;
437         case LOBYTE_ONLY: 
438         case LOBYTE_HIBYTE:
439             ch->access_state = WAITING_LOBYTE;
440             break;
441     }
442
443
444     switch (cmd.op_mode) {
445         case IRQ_ON_TERM_CNT:
446             ch->output_pin = 0;
447             break;
448         case ONE_SHOT: 
449             ch->output_pin = 1;
450             break;
451         case RATE_GEN: 
452             ch->output_pin = 1;
453             break;
454         case SQR_WAVE:
455             ch->output_pin = 1;
456             break;
457         case SW_STROBE:
458             ch->output_pin = 1;
459             break;
460         default:
461             PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
462             return -1;
463     }
464
465     return 0;
466     
467 }
468
469
470
471
472 static int pit_read_channel(struct guest_info * core, ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
473     struct pit * state = (struct pit *)dev->private_data;
474     char * val = (char *)dst;
475
476     if (length != 1) {
477         PrintError("8254 PIT: Invalid Read Write length \n");
478         return -1;
479     }
480
481     PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
482
483     switch (port) {
484         case CHANNEL0_PORT: 
485             if (handle_channel_read(&(state->ch_0), val) == -1) {
486                 PrintError("CHANNEL0 read error\n");
487                 return -1;
488             }
489             break;
490         case CHANNEL1_PORT:
491             if (handle_channel_read(&(state->ch_1), val) == -1) {
492                 PrintError("CHANNEL1 read error\n");
493                 return -1;
494             }
495             break;
496         case CHANNEL2_PORT:
497             if (handle_channel_read(&(state->ch_2), val) == -1) {
498                 PrintError("CHANNEL2 read error\n");
499                 return -1;
500             }
501             break;
502         default:
503             PrintError("8254 PIT: Read from invalid port (%d)\n", port);
504             return -1;
505     }
506
507     return length;
508 }
509
510
511
512 static int pit_write_channel(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
513     struct pit * state = (struct pit *)dev->private_data;
514     char val = *(char *)src;
515
516     if (length != 1) {
517         PrintError("8254 PIT: Invalid Write Length\n");
518         return -1;
519     }
520
521     PrintDebug("8254 PIT: Write to PIT Channel %d (%x)\n", port - CHANNEL0_PORT, *(char*)src);
522
523
524     switch (port) {
525         case CHANNEL0_PORT:
526             if (handle_channel_write(&(state->ch_0), val) == -1) {
527                 PrintError("CHANNEL0 write error\n");
528                 return -1;
529             } 
530             break;
531         case CHANNEL1_PORT:
532             if (handle_channel_write(&(state->ch_1), val) == -1) {
533                 PrintError("CHANNEL1 write error\n");
534                 return -1;
535             }
536             break;
537         case CHANNEL2_PORT:
538             if (handle_channel_write(&(state->ch_2), val) == -1) {
539                 PrintError("CHANNEL2 write error\n");   
540                 return -1;
541             }
542             break;
543         default:
544             PrintError("8254 PIT: Write to invalid port (%d)\n", port);
545             return -1;
546     }
547
548     return length;
549 }
550
551
552
553
554 static int pit_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
555     struct pit * state = (struct pit *)dev->private_data;
556     struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
557
558     PrintDebug("8254 PIT: Write to PIT Command port\n");
559     PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
560     if (length != 1) {
561         PrintError("8254 PIT: Write of Invalid length to command port\n");
562         return -1;
563     }
564
565     switch (cmd->channel) {
566         case 0:
567             if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
568                 PrintError("CHANNEL0 command error\n");
569                 return -1;
570             }
571             break;
572         case 1:
573             if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
574                 PrintError("CHANNEL1 command error\n");
575                 return -1;
576             }
577             break;
578         case 2:
579             if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
580                 PrintError("CHANNEL2 command error\n");
581                 return -1;
582             }
583             break;
584         case 3:
585             // Read Back command
586             PrintError("Read back command not implemented\n");
587             return -1;
588             break;
589         default:
590             break;
591     }
592
593
594     return length;
595 }
596
597
598
599
600 static struct vm_timer_ops timer_ops = {
601     .update_time = pit_update_time,
602     .advance_timer = pit_advance_time,
603 };
604
605
606 static void init_channel(struct channel * ch) {
607     ch->run_state = NOT_RUNNING;
608     ch->access_state = NOT_WAITING;
609     ch->access_mode = 0;
610     ch->op_mode = 0;
611
612     ch->counter = 0;
613     ch->reload_value = 0;
614     ch->output_pin = 0;
615     ch->gate_input_pin = 0;
616
617     ch->latched_value = 0;
618     ch->latch_state = NOTLATCHED;
619     ch->read_state = LSB;
620
621     return;
622 }
623
624
625
626
627 static int pit_free(struct vm_device * dev) {
628
629     return 0;
630 }
631
632
633 static struct v3_device_ops dev_ops = {
634     .free = pit_free,
635     .reset = NULL,
636     .start = NULL,
637     .stop = NULL,
638
639 };
640
641 #include <palacios/vm_guest.h>
642
643 static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
644     struct pit * pit_state = NULL;
645     struct vm_device * dev = NULL;
646     char * name = v3_cfg_val(cfg, "name");
647     
648     // PIT is only usable in non-multicore environments
649     // just hardcode the core context
650     struct guest_info * info = &(vm->cores[0]);
651
652     uint_t cpu_khz = V3_CPU_KHZ();
653     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
654
655     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
656     V3_ASSERT(pit_state != NULL);
657
658     dev = v3_allocate_device(name, &dev_ops, pit_state);
659
660     if (v3_attach_device(vm, dev) == -1) {
661         PrintError("Could not attach device %s\n", name);
662         return -1;
663     }
664
665     v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
666     v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
667     v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
668     v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
669
670 #ifdef CONFIG_DEBUG_PIT
671     PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
672     PrintTraceLL(reload_val);
673     PrintDebug("\n");
674 #endif
675
676     
677     v3_add_timer(info, &timer_ops, dev);
678
679     // Get cpu frequency and calculate the global pit oscilattor counter/cycle
680
681     do_divll(reload_val, OSC_HZ);
682     pit_state->pit_counter = reload_val;
683     pit_state->pit_reload = reload_val;
684
685
686
687     init_channel(&(pit_state->ch_0));
688     init_channel(&(pit_state->ch_1));
689     init_channel(&(pit_state->ch_2));
690
691 #ifdef CONFIG_DEBUG_PIT
692     PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
693     PrintTraceLL(pit_state->pit_counter);
694     PrintDebug("\n");
695 #endif
696
697     return 0;
698 }
699
700
701 device_register("8254_PIT", pit_init);