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.


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