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.


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