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.


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