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.


large scale namespace changes
[palacios.git] / palacios / src / devices / 8254.c
index 8dbe05e..7a81595 100644 (file)
@@ -1,11 +1,34 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
 #include <devices/8254.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_time.h>
 #include <palacios/vmm_util.h>
+#include <palacios/vmm_intr.h>
 
 
 
-
+#ifndef DEBUG_PIT
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
 
 
 
@@ -44,6 +67,12 @@ struct channel {
   ushort_t counter;
   ushort_t reload_value;
 
+  ushort_t latched_value;
+  
+  enum {NOTLATCHED, LATCHED} latch_state;
+
+  enum {LSB, MSB} read_state;
+
   uint_t output_pin : 1;
   uint_t gate_input_pin : 1;
 };
@@ -96,37 +125,50 @@ static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint
   uint_t channel_cycles = 0;
   uint_t output_changed = 0;
   
-  PrintDebug("8254 PIT: %d crystal tics\n", oscillations);
+  // PrintDebug("8254 PIT: %d crystal tics\n", oscillations);
   if (ch->run_state == PENDING) {
     oscillations--;
     ch->counter = ch->reload_value;
+
+    if (ch->op_mode == SQR_WAVE) {
+      ch->counter -= ch->counter % 2;
+    }
+
     ch->run_state = RUNNING;
   } else if (ch->run_state != RUNNING) {
     return output_changed;
   }
 
-
+  /*
   PrintDebug("8254 PIT: Channel Run State = %d, counter=", ch->run_state);
   PrintTraceLL(ch->counter);
   PrintDebug("\n");
-
+  */
+  if (ch->op_mode == SQR_WAVE) {
+    oscillations *= 2;
+  }
 
   if (ch->counter > oscillations) {
     ch->counter -= oscillations;
     return output_changed;
   } else {
+    ushort_t reload_val = ch->reload_value; 
     oscillations -= ch->counter;
     ch->counter = 0;
     channel_cycles = 1;
 
     
-    channel_cycles += oscillations / ch->reload_value;
-    oscillations = oscillations % ch->reload_value;
+    if (ch->op_mode == SQR_WAVE) {
+      reload_val -= reload_val % 2;
+    }
+    
+    channel_cycles += oscillations / reload_val;
+    oscillations = oscillations % reload_val;
 
-    ch->counter = ch->reload_value - oscillations;
+    ch->counter = reload_val - oscillations;
   }
 
-  PrintDebug("8254 PIT: Channel Cycles: %d\n", channel_cycles);
+  //  PrintDebug("8254 PIT: Channel Cycles: %d\n", channel_cycles);
   
 
 
@@ -150,10 +192,18 @@ static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint
     }
     break;
   case SQR_WAVE:
+    ch->output_pin = (ch->output_pin + 1) % 2;
+
+    if (ch->output_pin == 1) {
+      output_changed = 1;
+    }
+
     break;
   case SW_STROBE:
+    return -1;
     break;
   case HW_STROBE:
+    return -1;
     break;
   default:
     break;
@@ -212,7 +262,7 @@ static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priva
     if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
       // raise interrupt
       PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
-      dev->vm->vm_ops.raise_irq(dev->vm, 0);
+      v3_raise_irq(dev->vm, 0);
     }
 
     //handle_crystal_tics(dev, &(state->ch_1), oscillations);
@@ -254,20 +304,20 @@ static int handle_channel_write(struct channel * ch, char val) {
     case WAITING_LOBYTE:
       ch->reload_value &= 0xff00;
       ch->reload_value |= val;
-
+      
       if (ch->access_mode == LOBYTE_HIBYTE) {
        ch->access_state = WAITING_HIBYTE;
       } else if ((ch->op_mode != RATE_GEN) || (ch->run_state != RUNNING)) {
        ch->run_state = PENDING;
       }
-
+      
       PrintDebug("8254 PIT: updated channel counter: %d\n", ch->reload_value);
       PrintDebug("8254 PIT: Channel Run State=%d\n", ch->run_state);
       break;
     default:
       return -1;
-  }
-
+    }
+    
 
     switch (ch->op_mode) {
     case IRQ_ON_TERM_CNT:
@@ -279,8 +329,9 @@ static int handle_channel_write(struct channel * ch, char val) {
     case RATE_GEN:
       ch->output_pin = 1;
       break;
-
-
+    case SQR_WAVE:
+      ch->output_pin = 1;
+      break;
     default:
       return -1;
       break;
@@ -292,7 +343,28 @@ static int handle_channel_write(struct channel * ch, char val) {
 
 
 static int handle_channel_read(struct channel * ch, char * val) {
-  return -1;
+
+  ushort_t * myval;
+
+  if (ch->latch_state == NOTLATCHED) { 
+    myval = &(ch->counter);
+  } else {
+    myval = &(ch->latched_value);
+  }
+
+  if (ch->read_state == LSB) { 
+    *val = ((char*)myval)[0];  // little endian
+    ch->read_state = MSB;
+  } else {
+    *val = ((char*)myval)[1];
+    ch->read_state = LSB;
+    if (ch->latch_state == LATCHED) { 
+      ch->latch_state = NOTLATCHED;
+    }
+  }
+
+  return 0;
+
 }
 
 
@@ -308,7 +380,10 @@ static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
 
   switch (cmd.access_mode) {
   case LATCH_COUNT:
-    return -1;
+    if (ch->latch_state == NOTLATCHED) { 
+      ch->latched_value = ch->counter;
+      ch->latch_state = LATCHED;
+    }
     break;
   case HIBYTE_ONLY:
     ch->access_state = WAITING_HIBYTE;
@@ -349,7 +424,7 @@ static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_
   char * val = (char *)dst;
 
   if (length != 1) {
-    PrintDebug("8254 PIT: Invalid Read Write length \n");
+    PrintError("8254 PIT: Invalid Read Write length \n");
     return -1;
   }
 
@@ -372,7 +447,7 @@ static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_
     }
     break;
   default:
-    PrintDebug("8254 PIT: Read from invalid port (%d)\n", port);
+    PrintError("8254 PIT: Read from invalid port (%d)\n", port);
     return -1;
   }
 
@@ -386,7 +461,7 @@ static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm
   char val = *(char *)src;
 
   if (length != 1) {
-    PrintDebug("8254 PIT: Invalid Write Length\n");
+    PrintError("8254 PIT: Invalid Write Length\n");
     return -1;
   }
 
@@ -410,7 +485,7 @@ static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm
     }
     break;
   default:
-    PrintDebug("8254 PIT: Write to invalid port (%d)\n", port);
+    PrintError("8254 PIT: Write to invalid port (%d)\n", port);
     return -1;
   }
 
@@ -427,7 +502,7 @@ static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm
   PrintDebug("8254 PIT: Write to PIT Command port\n");
   PrintDebug("8254 PIT: Writing to channel %d (access_mode = %d, op_mode = %d)\n", cmd->channel, cmd->access_mode, cmd->op_mode);
   if (length != 1) {
-    PrintDebug("8254 PIT: Write of Invalid length to command port\n");
+    PrintError("8254 PIT: Write of Invalid length to command port\n");
     return -1;
   }
 
@@ -478,6 +553,10 @@ static void init_channel(struct channel * ch) {
   ch->output_pin = 0;
   ch->gate_input_pin = 0;
 
+  ch->latched_value = 0;
+  ch->latch_state = NOTLATCHED;
+  ch->read_state = LSB;
+
   return;
 }
 
@@ -487,15 +566,16 @@ static int pit_init(struct vm_device * dev) {
   uint_t cpu_khz = V3_CPU_KHZ();
   ullong_t reload_val = (ullong_t)cpu_khz * 1000;
 
-  dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
+  v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
 
+#ifdef DEBUG_PIT
   PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
   PrintTraceLL(reload_val);
   PrintDebug("\n");
-
+#endif
 
   v3_add_timer(dev->vm, &timer_ops, dev);
 
@@ -511,9 +591,11 @@ static int pit_init(struct vm_device * dev) {
   init_channel(&(state->ch_1));
   init_channel(&(state->ch_2));
 
+#ifdef DEBUG_PIT
   PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
   PrintTraceLL(state->pit_counter);
   PrintDebug("\n");
+#endif
 
   return 0;
 }
@@ -534,12 +616,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_pit() {
+struct vm_device * v3_create_pit() {
   struct pit * pit_state = NULL;
   pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
   V3_ASSERT(pit_state != NULL);
 
-  struct vm_device * dev = create_device("PIT", &dev_ops, pit_state);
+  struct vm_device * dev = v3_create_device("PIT", &dev_ops, pit_state);
   
   return dev;
 }