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.


added error reporting functions
[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             PrintError("Software strobe not implemented\n");
210             return -1;
211             break;
212         case HW_STROBE:
213             PrintError("Hardware strobe not implemented\n");
214             return -1;
215             break;
216         default:
217             break;
218     }
219
220     return output_changed;
221 }
222                                 
223
224
225 static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
226     struct vm_device * dev = (struct vm_device *)private_data;
227     struct pit * state = (struct pit *)dev->private_data;
228     //  ullong_t tmp_ctr = state->pit_counter;
229     ullong_t tmp_cycles;
230     uint_t oscillations = 0;
231
232
233     /*
234       PrintDebug("updating cpu_cycles=");
235       PrintTraceLL(cpu_cycles);
236       PrintDebug("\n");
237     
238       PrintDebug("pit_counter=");
239       PrintTraceLL(state->pit_counter);
240       PrintDebug("\n");
241     
242       PrintDebug("pit_reload=");
243       PrintTraceLL(state->pit_reload);
244       PrintDebug("\n");
245     */
246
247     if (state->pit_counter > cpu_cycles) {
248         // Easy...
249         state->pit_counter -= cpu_cycles;
250     } else {
251         ushort_t reload_val = state->pit_reload;
252         // Take off the first part
253         cpu_cycles -= state->pit_counter;
254         state->pit_counter = 0;
255         oscillations = 1;
256     
257         if (cpu_cycles > state->pit_reload) {
258             // how many full oscillations
259       
260             //PrintError("cpu_cycles = %p, reload = %p...\n", 
261             //   (void *)(addr_t)cpu_cycles, 
262             //   (void *)(addr_t)state->pit_reload);
263
264             // How do we check for a one shot....
265             if (state->pit_reload == 0) {
266                 reload_val = 1;
267             }
268
269             tmp_cycles = cpu_cycles;
270
271       
272 #ifdef __V3_64BIT__
273             cpu_cycles = tmp_cycles % state->pit_reload;
274             tmp_cycles = tmp_cycles / state->pit_reload;
275 #else
276             cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
277 #endif
278         
279             oscillations += tmp_cycles;
280         }
281
282         // update counter with remainder (mod reload)
283         state->pit_counter = state->pit_reload - cpu_cycles;    
284
285         //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
286         if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
287             // raise interrupt
288             PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
289             v3_raise_irq(dev->vm, 0);
290         }
291
292         //handle_crystal_tics(dev, &(state->ch_1), oscillations);
293         //handle_crystal_tics(dev, &(state->ch_2), oscillations);
294     }
295   
296
297
298  
299     return;
300 }
301
302
303
304 /* This should call out to handle_SQR_WAVE_write, etc...
305  */
306 static int handle_channel_write(struct channel * ch, char val) {
307
308     switch (ch->access_state) {      
309         case WAITING_HIBYTE:
310             {
311                 ushort_t tmp_val = ((ushort_t)val) << 8;
312                 ch->reload_value &= 0x00ff;
313                 ch->reload_value |= tmp_val;
314         
315
316                 if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)){
317                     ch->run_state = PENDING;  
318                 }
319         
320                 if (ch->access_mode == LOBYTE_HIBYTE) {
321                     ch->access_state = WAITING_LOBYTE;
322                 }
323
324                 PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);        
325                 PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
326                 break;
327             }
328         case WAITING_LOBYTE:
329             ch->reload_value &= 0xff00;
330             ch->reload_value |= val;
331       
332             if (ch->access_mode == LOBYTE_HIBYTE) {
333                 ch->access_state = WAITING_HIBYTE;
334             } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
335                 ch->run_state = PENDING;
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         default:
342             PrintError("Invalid Access state\n");
343             return -1;
344     }
345     
346
347     switch (ch->op_mode) {
348         case IRQ_ON_TERM_CNT:
349             ch->output_pin = 0;
350             break;
351         case ONE_SHOT:
352             ch->output_pin = 1;
353             break;
354         case RATE_GEN:
355             ch->output_pin = 1;
356             break;
357         case SQR_WAVE:
358             ch->output_pin = 1;
359             break;
360         default:
361             PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
362             return -1;
363             break;
364     }
365
366
367     return 0;
368 }
369
370
371 static int handle_channel_read(struct channel * ch, char * val) {
372
373     ushort_t * myval;
374
375     if (ch->latch_state == NOTLATCHED) { 
376         myval = &(ch->counter);
377     } else {
378         myval = &(ch->latched_value);
379     }
380
381     if (ch->read_state == LSB) { 
382         *val = ((char*)myval)[0];  // little endian
383         ch->read_state = MSB;
384     } else {
385         *val = ((char*)myval)[1];
386         ch->read_state = LSB;
387         if (ch->latch_state == LATCHED) { 
388             ch->latch_state = NOTLATCHED;
389         }
390     }
391
392     return 0;
393
394 }
395
396
397
398
399
400 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
401     ch->op_mode = cmd.op_mode;
402     ch->access_mode = cmd.access_mode;
403
404
405
406
407     switch (cmd.access_mode) {
408         case LATCH_COUNT:
409             if (ch->latch_state == NOTLATCHED) { 
410                 ch->latched_value = ch->counter;
411                 ch->latch_state = LATCHED;
412             }
413             break;
414         case HIBYTE_ONLY:
415             ch->access_state = WAITING_HIBYTE;
416             break;
417         case LOBYTE_ONLY: 
418         case LOBYTE_HIBYTE:
419             ch->access_state = WAITING_LOBYTE;
420             break;
421     }
422
423
424     switch (cmd.op_mode) {
425         case IRQ_ON_TERM_CNT:
426             ch->output_pin = 0;
427             break;
428         case ONE_SHOT: 
429             ch->output_pin = 1;
430             break;
431         case RATE_GEN: 
432             ch->output_pin = 1;
433             break;
434         case SQR_WAVE:
435             ch->output_pin = 1;
436             break;
437         default:
438             PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
439             return -1;
440     }
441
442     return 0;
443     
444 }
445
446
447
448
449 static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
450     struct pit * state = (struct pit *)dev->private_data;
451     char * val = (char *)dst;
452
453     if (length != 1) {
454         PrintError("8254 PIT: Invalid Read Write length \n");
455         return -1;
456     }
457
458     PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
459
460     switch (port) {
461         case CHANNEL0_PORT: 
462             if (handle_channel_read(&(state->ch_0), val) == -1) {
463                 PrintError("CHANNEL0 read error\n");
464                 return -1;
465             }
466             break;
467         case CHANNEL1_PORT:
468             if (handle_channel_read(&(state->ch_1), val) == -1) {
469                 PrintError("CHANNEL1 read error\n");
470                 return -1;
471             }
472             break;
473         case CHANNEL2_PORT:
474             if (handle_channel_read(&(state->ch_2), val) == -1) {
475                 PrintError("CHANNEL2 read error\n");
476                 return -1;
477             }
478             break;
479         default:
480             PrintError("8254 PIT: Read from invalid port (%d)\n", port);
481             return -1;
482     }
483
484     return length;
485 }
486
487
488
489 static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
490     struct pit * state = (struct pit *)dev->private_data;
491     char val = *(char *)src;
492
493     if (length != 1) {
494         PrintError("8254 PIT: Invalid Write Length\n");
495         return -1;
496     }
497
498     PrintDebug("8254 PIT: Write to PIT Channel %d (%x)\n", port - CHANNEL0_PORT, *(char*)src);
499
500
501     switch (port) {
502         case CHANNEL0_PORT:
503             if (handle_channel_write(&(state->ch_0), val) == -1) {
504                 PrintError("CHANNEL0 write error\n");
505                 return -1;
506             } 
507             break;
508         case CHANNEL1_PORT:
509             if (handle_channel_write(&(state->ch_1), val) == -1) {
510                 PrintError("CHANNEL1 write error\n");
511                 return -1;
512             }
513             break;
514         case CHANNEL2_PORT:
515             if (handle_channel_write(&(state->ch_2), val) == -1) {
516                 PrintError("CHANNEL2 write error\n");   
517                 return -1;
518             }
519             break;
520         default:
521             PrintError("8254 PIT: Write to invalid port (%d)\n", port);
522             return -1;
523     }
524
525     return length;
526 }
527
528
529
530
531 static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
532     struct pit * state = (struct pit *)dev->private_data;
533     struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
534
535     PrintDebug("8254 PIT: Write to PIT Command port\n");
536     PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
537     if (length != 1) {
538         PrintError("8254 PIT: Write of Invalid length to command port\n");
539         return -1;
540     }
541
542     switch (cmd->channel) {
543         case 0:
544             if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
545                 PrintError("CHANNEL0 command error\n");
546                 return -1;
547             }
548             break;
549         case 1:
550             if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
551                 PrintError("CHANNEL1 command error\n");
552                 return -1;
553             }
554             break;
555         case 2:
556             if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
557                 PrintError("CHANNEL2 command error\n");
558                 return -1;
559             }
560             break;
561         case 3:
562             // Read Back command
563             PrintError("Read back command not implemented\n");
564             return -1;
565             break;
566         default:
567             break;
568     }
569
570
571     return length;
572 }
573
574
575
576
577 static struct vm_timer_ops timer_ops = {
578     .update_time = pit_update_time,
579 };
580
581
582 static void init_channel(struct channel * ch) {
583     ch->run_state = NOT_RUNNING;
584     ch->access_state = NOT_WAITING;
585     ch->access_mode = 0;
586     ch->op_mode = 0;
587
588     ch->counter = 0;
589     ch->reload_value = 0;
590     ch->output_pin = 0;
591     ch->gate_input_pin = 0;
592
593     ch->latched_value = 0;
594     ch->latch_state = NOTLATCHED;
595     ch->read_state = LSB;
596
597     return;
598 }
599
600
601 static int pit_init(struct vm_device * dev) {
602     struct pit * state = (struct pit *)dev->private_data;
603     uint_t cpu_khz = V3_CPU_KHZ();
604     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
605
606     v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
607     v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
608     v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
609     v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
610
611 #ifdef DEBUG_PIT
612     PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
613     PrintTraceLL(reload_val);
614     PrintDebug("\n");
615 #endif
616
617     v3_add_timer(dev->vm, &timer_ops, dev);
618
619     // Get cpu frequency and calculate the global pit oscilattor counter/cycle
620
621     do_divll(reload_val, OSC_HZ);
622     state->pit_counter = reload_val;
623     state->pit_reload = reload_val;
624
625
626
627     init_channel(&(state->ch_0));
628     init_channel(&(state->ch_1));
629     init_channel(&(state->ch_2));
630
631 #ifdef DEBUG_PIT
632     PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
633     PrintTraceLL(state->pit_counter);
634     PrintDebug("\n");
635 #endif
636
637     return 0;
638 }
639
640 static int pit_deinit(struct vm_device * dev) {
641
642     return 0;
643 }
644
645
646 static struct vm_device_ops dev_ops = {
647     .init = pit_init,
648     .deinit = pit_deinit,
649     .reset = NULL,
650     .start = NULL,
651     .stop = NULL,
652
653 };
654
655
656 struct vm_device * v3_create_pit() {
657     struct pit * pit_state = NULL;
658     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
659     V3_ASSERT(pit_state != NULL);
660
661     struct vm_device * dev = v3_create_device("PIT", &dev_ops, pit_state);
662   
663     return dev;
664 }