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.


reworked device IO hook framework
[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 vm_device * dev, 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 vm_device * dev = (struct vm_device *)private_data;
243     struct pit * state = (struct pit *)dev->private_data;
244     //  ullong_t tmp_ctr = state->pit_counter;
245     ullong_t tmp_cycles;
246     uint_t oscillations = 0;
247
248
249     /*
250       PrintDebug("updating cpu_cycles=");
251       PrintTraceLL(cpu_cycles);
252       PrintDebug("\n");
253     
254       PrintDebug("pit_counter=");
255       PrintTraceLL(state->pit_counter);
256       PrintDebug("\n");
257     
258       PrintDebug("pit_reload=");
259       PrintTraceLL(state->pit_reload);
260       PrintDebug("\n");
261     */
262
263     if (state->pit_counter > cpu_cycles) {
264         // Easy...
265         state->pit_counter -= cpu_cycles;
266     } else {
267         ushort_t reload_val = state->pit_reload;
268         // Take off the first part
269         cpu_cycles -= state->pit_counter;
270         state->pit_counter = 0;
271         oscillations = 1;
272     
273         if (cpu_cycles > state->pit_reload) {
274             // how many full oscillations
275       
276             //PrintError("cpu_cycles = %p, reload = %p...\n", 
277             //   (void *)(addr_t)cpu_cycles, 
278             //   (void *)(addr_t)state->pit_reload);
279
280             // How do we check for a one shot....
281             if (state->pit_reload == 0) {
282                 reload_val = 1;
283             }
284
285             tmp_cycles = cpu_cycles;
286
287       
288 #ifdef __V3_64BIT__
289             cpu_cycles = tmp_cycles % state->pit_reload;
290             tmp_cycles = tmp_cycles / state->pit_reload;
291 #else
292             cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
293 #endif
294         
295             oscillations += tmp_cycles;
296         }
297
298         // update counter with remainder (mod reload)
299         state->pit_counter = state->pit_reload - cpu_cycles;    
300
301         //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
302         if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
303             // raise interrupt
304             PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
305             v3_raise_irq(info->vm_info, 0);
306         }
307
308         //handle_crystal_tics(dev, &(state->ch_1), oscillations);
309         handle_crystal_tics(dev, &(state->ch_2), oscillations);
310     }
311   
312
313
314  
315     return;
316 }
317
318 /* This should call out to handle_SQR_WAVE_write, etc...
319  */
320 static int handle_channel_write(struct channel * ch, char val) {
321
322     switch (ch->access_state) {      
323         case WAITING_HIBYTE:
324             {
325                 ushort_t tmp_val = ((ushort_t)val) << 8;
326                 ch->reload_value &= 0x00ff;
327                 ch->reload_value |= tmp_val;
328         
329
330                 if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)){
331                     ch->run_state = PENDING;  
332                 }
333         
334                 if (ch->access_mode == LOBYTE_HIBYTE) {
335                     ch->access_state = WAITING_LOBYTE;
336                 }
337
338                 PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);        
339                 PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
340                 break;
341             }
342         case WAITING_LOBYTE:
343             ch->reload_value &= 0xff00;
344             ch->reload_value |= val;
345       
346             if (ch->access_mode == LOBYTE_HIBYTE) {
347                 ch->access_state = WAITING_HIBYTE;
348             } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
349                 ch->run_state = PENDING;
350             }
351       
352             PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);
353             PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
354             break;
355         default:
356             PrintError("Invalid Access state\n");
357             return -1;
358     }
359     
360
361     switch (ch->op_mode) {
362         case IRQ_ON_TERM_CNT:
363             ch->output_pin = 0;
364             break;
365         case ONE_SHOT:
366             ch->output_pin = 1;
367             break;
368         case RATE_GEN:
369             ch->output_pin = 1;
370             break;
371         case SQR_WAVE:
372             ch->output_pin = 1;
373             break;
374         case SW_STROBE:
375             ch->output_pin = 1;
376             break;
377         default:
378             PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
379             return -1;
380             break;
381     }
382
383
384     return 0;
385 }
386
387
388 static int handle_channel_read(struct channel * ch, char * val) {
389
390     ushort_t * myval;
391
392     if (ch->latch_state == NOTLATCHED) { 
393         myval = &(ch->counter);
394     } else {
395         myval = &(ch->latched_value);
396     }
397
398     if (ch->read_state == LSB) { 
399         *val = ((char*)myval)[0];  // little endian
400         ch->read_state = MSB;
401     } else {
402         *val = ((char*)myval)[1];
403         ch->read_state = LSB;
404         if (ch->latch_state == LATCHED) { 
405             ch->latch_state = NOTLATCHED;
406         }
407     }
408
409     return 0;
410
411 }
412
413 static int handle_speaker_read(uint8_t *speaker, struct channel * ch, char * val) {
414     *val = *speaker;
415
416     if ((*speaker & PIT_SPEAKER_GATE)) {
417         *val |= (ch->output_pin << 5);
418     }
419     
420     return 0;
421 }
422
423 static int handle_speaker_write(uint8_t *speaker, struct channel * ch, char val) {
424     *speaker = (val & ~0x20);
425     return 0;
426 }
427
428 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
429     ch->op_mode = cmd.op_mode;
430     ch->access_mode = cmd.access_mode;
431
432
433
434
435     switch (cmd.access_mode) {
436         case LATCH_COUNT:
437             if (ch->latch_state == NOTLATCHED) { 
438                 ch->latched_value = ch->counter;
439                 ch->latch_state = LATCHED;
440             }
441             break;
442         case HIBYTE_ONLY:
443             ch->access_state = WAITING_HIBYTE;
444             break;
445         case LOBYTE_ONLY: 
446         case LOBYTE_HIBYTE:
447             ch->access_state = WAITING_LOBYTE;
448             break;
449     }
450
451
452     switch (cmd.op_mode) {
453         case IRQ_ON_TERM_CNT:
454             ch->output_pin = 0;
455             break;
456         case ONE_SHOT: 
457             ch->output_pin = 1;
458             break;
459         case RATE_GEN: 
460             ch->output_pin = 1;
461             break;
462         case SQR_WAVE:
463             ch->output_pin = 1;
464             break;
465         case SW_STROBE:
466             ch->output_pin = 1;
467             break;
468         default:
469             PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
470             return -1;
471     }
472
473     return 0;
474     
475 }
476
477
478
479
480 static int pit_read_channel(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
481     struct pit * state = (struct pit *)priv_data;
482     char * val = (char *)dst;
483
484     if (length != 1) {
485         PrintError("8254 PIT: Invalid Read Write length \n");
486         return -1;
487     }
488
489     PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
490
491     switch (port) {
492         case CHANNEL0_PORT: 
493             if (handle_channel_read(&(state->ch_0), val) == -1) {
494                 PrintError("CHANNEL0 read error\n");
495                 return -1;
496             }
497             break;
498         case CHANNEL1_PORT:
499             if (handle_channel_read(&(state->ch_1), val) == -1) {
500                 PrintError("CHANNEL1 read error\n");
501                 return -1;
502             }
503             break;
504         case CHANNEL2_PORT:
505             if (handle_channel_read(&(state->ch_2), val) == -1) {
506                 PrintError("CHANNEL2 read error\n");
507                 return -1;
508             }
509             break;
510         case SPEAKER_PORT:
511             if (handle_speaker_read(&state->speaker, &(state->ch_2), val) == -1) {
512                 PrintError("SPEAKER read error\n");
513                 return -1;
514             }
515             break;
516         default:
517             PrintError("8254 PIT: Read from invalid port (%d)\n", port);
518             return -1;
519     }
520
521     return length;
522 }
523
524
525
526 static int pit_write_channel(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
527     struct pit * state = (struct pit *)priv_data;
528     char val = *(char *)src;
529
530     if (length != 1) {
531         PrintError("8254 PIT: Invalid Write Length\n");
532         return -1;
533     }
534
535     PrintDebug("8254 PIT: Write to PIT Channel %d (%x)\n", port - CHANNEL0_PORT, *(char*)src);
536
537
538     switch (port) {
539         case CHANNEL0_PORT:
540             if (handle_channel_write(&(state->ch_0), val) == -1) {
541                 PrintError("CHANNEL0 write error\n");
542                 return -1;
543             } 
544             break;
545         case CHANNEL1_PORT:
546             if (handle_channel_write(&(state->ch_1), val) == -1) {
547                 PrintError("CHANNEL1 write error\n");
548                 return -1;
549             }
550             break;
551         case CHANNEL2_PORT:
552             if (handle_channel_write(&(state->ch_2), val) == -1) {
553                 PrintError("CHANNEL2 write error\n");   
554                 return -1;
555             }
556             break;
557         case SPEAKER_PORT:
558             if (handle_speaker_write(&state->speaker, &(state->ch_2), val) == -1) {
559                 PrintError("SPEAKER write error\n");
560                 return -1;
561             }
562             break;
563         default:
564             PrintError("8254 PIT: Write to invalid port (%d)\n", port);
565             return -1;
566     }
567
568     return length;
569 }
570
571
572
573
574 static int pit_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
575     struct pit * state = (struct pit *)priv_data;
576     struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
577
578     PrintDebug("8254 PIT: Write to PIT Command port\n");
579     PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
580     if (length != 1) {
581         PrintError("8254 PIT: Write of Invalid length to command port\n");
582         return -1;
583     }
584
585     switch (cmd->channel) {
586         case 0:
587             if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
588                 PrintError("CHANNEL0 command error\n");
589                 return -1;
590             }
591             break;
592         case 1:
593             if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
594                 PrintError("CHANNEL1 command error\n");
595                 return -1;
596             }
597             break;
598         case 2:
599             if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
600                 PrintError("CHANNEL2 command error\n");
601                 return -1;
602             }
603             break;
604         case 3:
605             // Read Back command
606             PrintError("Read back command not implemented\n");
607             return -1;
608             break;
609         default:
610             break;
611     }
612
613
614     return length;
615 }
616
617
618
619
620 static struct v3_timer_ops timer_ops = {
621     .update_timer = pit_update_timer,
622 };
623
624
625 static void init_channel(struct channel * ch) {
626     ch->run_state = NOT_RUNNING;
627     ch->access_state = NOT_WAITING;
628     ch->access_mode = 0;
629     ch->op_mode = 0;
630
631     ch->counter = 0;
632     ch->reload_value = 0;
633     ch->output_pin = 0;
634     ch->gate_input_pin = 0;
635
636     ch->latched_value = 0;
637     ch->latch_state = NOTLATCHED;
638     ch->read_state = LSB;
639
640     return;
641 }
642
643
644
645
646 static int pit_free(struct vm_device * dev) {
647     struct pit * state = (struct pit *)dev->private_data;
648     struct guest_info * info = &(dev->vm->cores[0]);
649
650
651     if (state->timer) {
652         v3_remove_timer(info, state->timer);
653     }
654  
655     V3_Free(state);
656     return 0;
657 }
658
659
660 static struct v3_device_ops dev_ops = {
661     .free = pit_free,
662     .reset = NULL,
663     .start = NULL,
664     .stop = NULL,
665
666 };
667
668 #include <palacios/vm_guest.h>
669
670 static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
671     struct pit * pit_state = NULL;
672     struct vm_device * dev = NULL;
673     char * dev_id = v3_cfg_val(cfg, "ID");
674     int ret = 0;
675
676     // PIT is only usable in non-multicore environments
677     // just hardcode the core context
678     struct guest_info * info = &(vm->cores[0]);
679
680     uint_t cpu_khz = V3_CPU_KHZ();
681     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
682
683     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
684     V3_ASSERT(pit_state != NULL);
685     pit_state->speaker = 0;
686
687     dev = v3_allocate_device(dev_id, &dev_ops, pit_state);
688
689     if (v3_attach_device(vm, dev) == -1) {
690         PrintError("Could not attach device %s\n", dev_id);
691         V3_Free(pit_state);
692         return -1;
693     }
694
695     ret |= v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
696     ret |= v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
697     ret |= v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
698     ret |= v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
699     ret |= v3_dev_hook_io(dev, SPEAKER_PORT, &pit_read_channel, &pit_write_channel);
700
701     if (ret != 0) {
702         PrintError("8254 PIT: Failed to hook IO ports\n");
703         v3_detach_device(dev);
704         return -1;
705     }
706
707 #ifdef CONFIG_DEBUG_PIT
708     PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
709     //PrintTrace(reload_val);
710     PrintDebug("\n");
711 #endif
712
713     
714
715     pit_state->timer = v3_add_timer(info, &timer_ops, dev);
716
717     if (pit_state->timer == NULL) {
718         v3_detach_device(dev);
719         return -1;
720     }
721
722     // Get cpu frequency and calculate the global pit oscilattor counter/cycle
723
724     do_divll(reload_val, OSC_HZ);
725     pit_state->pit_counter = reload_val;
726     pit_state->pit_reload = reload_val;
727
728
729     init_channel(&(pit_state->ch_0));
730     init_channel(&(pit_state->ch_1));
731     init_channel(&(pit_state->ch_2));
732
733 #ifdef CONFIG_DEBUG_PIT
734     PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
735     //PrintTraceLL(pit_state->pit_counter);
736     PrintDebug("\n");
737 #endif
738
739     return 0;
740 }
741
742
743 device_register("8254_PIT", pit_init);