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.


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