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