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