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.


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