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.


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