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