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.


integrated new configuration 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
235 static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
236     struct vm_device * dev = (struct vm_device *)private_data;
237     struct pit * state = (struct pit *)dev->private_data;
238     //  ullong_t tmp_ctr = state->pit_counter;
239     ullong_t tmp_cycles;
240     uint_t oscillations = 0;
241
242
243     /*
244       PrintDebug("updating cpu_cycles=");
245       PrintTraceLL(cpu_cycles);
246       PrintDebug("\n");
247     
248       PrintDebug("pit_counter=");
249       PrintTraceLL(state->pit_counter);
250       PrintDebug("\n");
251     
252       PrintDebug("pit_reload=");
253       PrintTraceLL(state->pit_reload);
254       PrintDebug("\n");
255     */
256
257     if (state->pit_counter > cpu_cycles) {
258         // Easy...
259         state->pit_counter -= cpu_cycles;
260     } else {
261         ushort_t reload_val = state->pit_reload;
262         // Take off the first part
263         cpu_cycles -= state->pit_counter;
264         state->pit_counter = 0;
265         oscillations = 1;
266     
267         if (cpu_cycles > state->pit_reload) {
268             // how many full oscillations
269       
270             //PrintError("cpu_cycles = %p, reload = %p...\n", 
271             //   (void *)(addr_t)cpu_cycles, 
272             //   (void *)(addr_t)state->pit_reload);
273
274             // How do we check for a one shot....
275             if (state->pit_reload == 0) {
276                 reload_val = 1;
277             }
278
279             tmp_cycles = cpu_cycles;
280
281       
282 #ifdef __V3_64BIT__
283             cpu_cycles = tmp_cycles % state->pit_reload;
284             tmp_cycles = tmp_cycles / state->pit_reload;
285 #else
286             cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
287 #endif
288         
289             oscillations += tmp_cycles;
290         }
291
292         // update counter with remainder (mod reload)
293         state->pit_counter = state->pit_reload - cpu_cycles;    
294
295         //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
296         if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
297             // raise interrupt
298             PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
299             v3_raise_irq(dev->vm, 0);
300         }
301
302         //handle_crystal_tics(dev, &(state->ch_1), oscillations);
303         //handle_crystal_tics(dev, &(state->ch_2), oscillations);
304     }
305   
306
307
308  
309     return;
310 }
311
312
313
314 /* This should call out to handle_SQR_WAVE_write, etc...
315  */
316 static int handle_channel_write(struct channel * ch, char val) {
317
318     switch (ch->access_state) {      
319         case WAITING_HIBYTE:
320             {
321                 ushort_t tmp_val = ((ushort_t)val) << 8;
322                 ch->reload_value &= 0x00ff;
323                 ch->reload_value |= tmp_val;
324         
325
326                 if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)){
327                     ch->run_state = PENDING;  
328                 }
329         
330                 if (ch->access_mode == LOBYTE_HIBYTE) {
331                     ch->access_state = WAITING_LOBYTE;
332                 }
333
334                 PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);        
335                 PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
336                 break;
337             }
338         case WAITING_LOBYTE:
339             ch->reload_value &= 0xff00;
340             ch->reload_value |= val;
341       
342             if (ch->access_mode == LOBYTE_HIBYTE) {
343                 ch->access_state = WAITING_HIBYTE;
344             } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
345                 ch->run_state = PENDING;
346             }
347       
348             PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);
349             PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
350             break;
351         default:
352             PrintError("Invalid Access state\n");
353             return -1;
354     }
355     
356
357     switch (ch->op_mode) {
358         case IRQ_ON_TERM_CNT:
359             ch->output_pin = 0;
360             break;
361         case ONE_SHOT:
362             ch->output_pin = 1;
363             break;
364         case RATE_GEN:
365             ch->output_pin = 1;
366             break;
367         case SQR_WAVE:
368             ch->output_pin = 1;
369             break;
370         case SW_STROBE:
371             ch->output_pin = 1;
372             break;
373         default:
374             PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
375             return -1;
376             break;
377     }
378
379
380     return 0;
381 }
382
383
384 static int handle_channel_read(struct channel * ch, char * val) {
385
386     ushort_t * myval;
387
388     if (ch->latch_state == NOTLATCHED) { 
389         myval = &(ch->counter);
390     } else {
391         myval = &(ch->latched_value);
392     }
393
394     if (ch->read_state == LSB) { 
395         *val = ((char*)myval)[0];  // little endian
396         ch->read_state = MSB;
397     } else {
398         *val = ((char*)myval)[1];
399         ch->read_state = LSB;
400         if (ch->latch_state == LATCHED) { 
401             ch->latch_state = NOTLATCHED;
402         }
403     }
404
405     return 0;
406
407 }
408
409
410
411
412
413 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
414     ch->op_mode = cmd.op_mode;
415     ch->access_mode = cmd.access_mode;
416
417
418
419
420     switch (cmd.access_mode) {
421         case LATCH_COUNT:
422             if (ch->latch_state == NOTLATCHED) { 
423                 ch->latched_value = ch->counter;
424                 ch->latch_state = LATCHED;
425             }
426             break;
427         case HIBYTE_ONLY:
428             ch->access_state = WAITING_HIBYTE;
429             break;
430         case LOBYTE_ONLY: 
431         case LOBYTE_HIBYTE:
432             ch->access_state = WAITING_LOBYTE;
433             break;
434     }
435
436
437     switch (cmd.op_mode) {
438         case IRQ_ON_TERM_CNT:
439             ch->output_pin = 0;
440             break;
441         case ONE_SHOT: 
442             ch->output_pin = 1;
443             break;
444         case RATE_GEN: 
445             ch->output_pin = 1;
446             break;
447         case SQR_WAVE:
448             ch->output_pin = 1;
449             break;
450         case SW_STROBE:
451             ch->output_pin = 1;
452             break;
453         default:
454             PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
455             return -1;
456     }
457
458     return 0;
459     
460 }
461
462
463
464
465 static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
466     struct pit * state = (struct pit *)dev->private_data;
467     char * val = (char *)dst;
468
469     if (length != 1) {
470         PrintError("8254 PIT: Invalid Read Write length \n");
471         return -1;
472     }
473
474     PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
475
476     switch (port) {
477         case CHANNEL0_PORT: 
478             if (handle_channel_read(&(state->ch_0), val) == -1) {
479                 PrintError("CHANNEL0 read error\n");
480                 return -1;
481             }
482             break;
483         case CHANNEL1_PORT:
484             if (handle_channel_read(&(state->ch_1), val) == -1) {
485                 PrintError("CHANNEL1 read error\n");
486                 return -1;
487             }
488             break;
489         case CHANNEL2_PORT:
490             if (handle_channel_read(&(state->ch_2), val) == -1) {
491                 PrintError("CHANNEL2 read error\n");
492                 return -1;
493             }
494             break;
495         default:
496             PrintError("8254 PIT: Read from invalid port (%d)\n", port);
497             return -1;
498     }
499
500     return length;
501 }
502
503
504
505 static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
506     struct pit * state = (struct pit *)dev->private_data;
507     char val = *(char *)src;
508
509     if (length != 1) {
510         PrintError("8254 PIT: Invalid Write Length\n");
511         return -1;
512     }
513
514     PrintDebug("8254 PIT: Write to PIT Channel %d (%x)\n", port - CHANNEL0_PORT, *(char*)src);
515
516
517     switch (port) {
518         case CHANNEL0_PORT:
519             if (handle_channel_write(&(state->ch_0), val) == -1) {
520                 PrintError("CHANNEL0 write error\n");
521                 return -1;
522             } 
523             break;
524         case CHANNEL1_PORT:
525             if (handle_channel_write(&(state->ch_1), val) == -1) {
526                 PrintError("CHANNEL1 write error\n");
527                 return -1;
528             }
529             break;
530         case CHANNEL2_PORT:
531             if (handle_channel_write(&(state->ch_2), val) == -1) {
532                 PrintError("CHANNEL2 write error\n");   
533                 return -1;
534             }
535             break;
536         default:
537             PrintError("8254 PIT: Write to invalid port (%d)\n", port);
538             return -1;
539     }
540
541     return length;
542 }
543
544
545
546
547 static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
548     struct pit * state = (struct pit *)dev->private_data;
549     struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
550
551     PrintDebug("8254 PIT: Write to PIT Command port\n");
552     PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
553     if (length != 1) {
554         PrintError("8254 PIT: Write of Invalid length to command port\n");
555         return -1;
556     }
557
558     switch (cmd->channel) {
559         case 0:
560             if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
561                 PrintError("CHANNEL0 command error\n");
562                 return -1;
563             }
564             break;
565         case 1:
566             if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
567                 PrintError("CHANNEL1 command error\n");
568                 return -1;
569             }
570             break;
571         case 2:
572             if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
573                 PrintError("CHANNEL2 command error\n");
574                 return -1;
575             }
576             break;
577         case 3:
578             // Read Back command
579             PrintError("Read back command not implemented\n");
580             return -1;
581             break;
582         default:
583             break;
584     }
585
586
587     return length;
588 }
589
590
591
592
593 static struct vm_timer_ops timer_ops = {
594     .update_time = pit_update_time,
595 };
596
597
598 static void init_channel(struct channel * ch) {
599     ch->run_state = NOT_RUNNING;
600     ch->access_state = NOT_WAITING;
601     ch->access_mode = 0;
602     ch->op_mode = 0;
603
604     ch->counter = 0;
605     ch->reload_value = 0;
606     ch->output_pin = 0;
607     ch->gate_input_pin = 0;
608
609     ch->latched_value = 0;
610     ch->latch_state = NOTLATCHED;
611     ch->read_state = LSB;
612
613     return;
614 }
615
616
617
618
619 static int pit_free(struct vm_device * dev) {
620
621     return 0;
622 }
623
624
625 static struct v3_device_ops dev_ops = {
626     .free = pit_free,
627     .reset = NULL,
628     .start = NULL,
629     .stop = NULL,
630
631 };
632
633
634 static int pit_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
635     struct pit * pit_state = NULL;
636     struct vm_device * dev = NULL;
637     char * name = v3_cfg_val(cfg, "name");
638
639     uint_t cpu_khz = V3_CPU_KHZ();
640     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
641
642     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
643     V3_ASSERT(pit_state != NULL);
644
645     dev = v3_allocate_device(name, &dev_ops, pit_state);
646
647     if (v3_attach_device(info, dev) == -1) {
648         PrintError("Could not attach device %s\n", name);
649         return -1;
650     }
651
652     v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
653     v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
654     v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
655     v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
656
657 #ifdef CONFIG_DEBUG_PIT
658     PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
659     PrintTraceLL(reload_val);
660     PrintDebug("\n");
661 #endif
662
663     v3_add_timer(info, &timer_ops, dev);
664
665     // Get cpu frequency and calculate the global pit oscilattor counter/cycle
666
667     do_divll(reload_val, OSC_HZ);
668     pit_state->pit_counter = reload_val;
669     pit_state->pit_reload = reload_val;
670
671
672
673     init_channel(&(pit_state->ch_0));
674     init_channel(&(pit_state->ch_1));
675     init_channel(&(pit_state->ch_2));
676
677 #ifdef CONFIG_DEBUG_PIT
678     PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
679     PrintTraceLL(pit_state->pit_counter);
680     PrintDebug("\n");
681 #endif
682
683     return 0;
684 }
685
686
687 device_register("8254_PIT", pit_init);