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.


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