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.


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