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 locking operations to devices interfacing with host events
[palacios.git] / palacios / src / devices / keyboard.c
index 28442c7..65e8797 100644 (file)
@@ -21,6 +21,8 @@
 #include <palacios/vmm.h>
 #include <palacios/vmm_types.h>
 
+#include <palacios/vmm_lock.h>
+
 
 #ifndef DEBUG_KEYBOARD
 #undef PrintDebug
@@ -146,6 +148,18 @@ struct keyboard_internal {
        // we wait for a new output byte on 60
        // then send it to the mouse
        IN_MOUSE,
+       // After the Keyboard LEDs are enabled
+       // we wait for the output byte on 64?
+       SET_LEDS,
+       // After the Keyboard SET_RATE is called
+       // we wait for the output byte on 64?
+       SET_RATE,
+       // The keyboard requests an ID which 
+       // generates 3 bytes of output...
+       KBD_ID1,
+       KBD_ID2,
+       
+       
     } state;
 
 
@@ -193,21 +207,31 @@ struct keyboard_internal {
 
     uchar_t input_byte;       //  input port of onboard uC
 
-    // Data for 8042
-    uchar_t input_queue;      //  
-    uint_t  input_queue_len;  //  
-    //uint_t  input_queue_read;
-    //uint_t  input_queue_write;
     // Data for system
     uchar_t output_queue;     //  
     uint_t  output_queue_len; //  
     //uint_t  output_queue_read;
     //uint_t  output_queue_write;
 
+    v3_lock_t kb_lock;
 
 };
 
 
+static int keyboard_interrupt(struct vm_device * dev, uint_t irq) {
+    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+
+    PrintDebug("keyboard: interrupt 0x%x\n", irq);
+
+    if (state->cmd_byte & CMD_INTR) { 
+       v3_raise_irq(dev->vm, irq);
+    }
+
+    return 0;
+}
+
+
+
 // 
 // push item onto outputqueue, optionally overwriting if there is no room
 // returns 0 if successful
@@ -229,12 +253,13 @@ static int PushToOutputQueue(struct vm_device * dev, uchar_t value, uchar_t over
     
        if (mouse) { 
            state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
-       } 
-
-       {
-           state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
+           keyboard_interrupt(dev, MOUSE_IRQ);
+       } else {
+           keyboard_interrupt(dev, KEYBOARD_IRQ);
        }
-    
+
+       state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
+
        return 0;
 
     } else {
@@ -243,7 +268,7 @@ static int PushToOutputQueue(struct vm_device * dev, uchar_t value, uchar_t over
     }
 }
 
-#if 1
+
 // 
 // pull item from outputqueue 
 // returns 0 if successful
@@ -276,64 +301,7 @@ static int PullFromOutputQueue(struct vm_device * dev, uchar_t * value)
        return -1;
     }
 }
-#endif
-
-#if 0
-// 
-// push item onto inputqueue, optionally overwriting if there is no room
-// returns 0 if successful
-//
-static int PushToInputQueue(struct vm_device * dev, uchar_t value, uchar_t overwrite) 
-{
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
-    if ((state->input_queue_len == 0) || overwrite) { 
-
-       state->input_queue = value;
-       state->input_queue_len = 1;
-       state->status_byte |= STATUS_INPUT_BUFFER_FULL;
-
-       return 0;
-    } else {
-       PrintError("keyboard: PushToOutputQueue Failed - Queue Full\n");
-       return -1;
-    }
-}
-
-// 
-// pull item from inputqueue 
-// returns 0 if successful
-//
-static int PullFromInputQueue(struct vm_device *dev, uchar_t *value) 
-{
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
-
-    if (state->input_queue_len == 1) { 
-
-       *value = state->input_queue;
-       state->input_queue_len = 0;
-       state->status_byte &= ~STATUS_INPUT_BUFFER_FULL;
-
-       return 0;
-    } else {
-       PrintError("keyboard: PullFromInputQueue Failed - Queue Empty\n");
-       return -1;
-    }
-}
-
-#endif
-
-
-
-
-static int keyboard_interrupt(struct vm_device * dev, uint_t irq) {
-    PrintDebug("keyboard: interrupt 0x%x\n", irq);
-
-    v3_raise_irq(dev->vm, irq);
-
-    return 0;
-
-}
 
 
 
@@ -344,16 +312,21 @@ static int key_event_handler(struct guest_info * info,
     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
-  
+
+    if (evt->scan_code == 0x44) { // F10 debug dump
+       v3_print_guest_state(info);
+       //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
+    }
+
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+
     if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
         && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
     
        PushToOutputQueue(dev, evt->scan_code, OVERWRITE, DATA, KEYBOARD);
-    
-       if (state->cmd_byte & CMD_INTR) { 
-           keyboard_interrupt(dev, KEYBOARD_IRQ);
-       }
     }
+
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
   
     return 0;
 }
@@ -364,10 +337,12 @@ static int mouse_event_handler(struct guest_info * info,
                               void * private_data) {
     struct vm_device * dev = (struct vm_device *)private_data;
     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
-
+    int ret = 0;
     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
               evt->data[0], evt->data[1], evt->data[2]);
   
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+
     memcpy(state->mouse_packet, evt->data, 3);
   
     state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
@@ -382,11 +357,15 @@ static int mouse_event_handler(struct guest_info * info,
            }
            break;
        default:
-           return -1;
+           PrintError("Invalid mouse state\n");
+           ret = -1;
            break;
     }
 
-    return 0;
+
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
+
+    return ret;
 }
 
 
@@ -803,6 +782,9 @@ static int keyboard_write_command(ushort_t port,
 
     cmd = *((uchar_t*)src); 
 
+
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+
     if (state->state != NORMAL) { 
        PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
     }
@@ -980,8 +962,9 @@ static int keyboard_write_command(ushort_t port,
            break;
     }
 
-    return 1;
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
 
+    return length;
 }
 
 static int keyboard_read_status(ushort_t port,
@@ -991,19 +974,21 @@ static int keyboard_read_status(ushort_t port,
 {
     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
-    if (length == 1) { 
-
-       PrintDebug("keyboard: read status (64h): ");
-
-       *((uchar_t*)dest) = state->status_byte;
-
-       PrintDebug("0x%x\n", *((uchar_t*)dest));
-
-       return 1;
-    } else {
+    if (length != 1) { 
        PrintError("keyboard: >1 byte read for status (64h)\n");
        return -1;
     }
+
+
+    PrintDebug("keyboard: read status (64h): ");
+
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+    *((uchar_t*)dest) = state->status_byte;
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    
+    PrintDebug("0x%x\n", *((uchar_t*)dest));
+    
+    return length;
 }
 
 static int keyboard_write_output(ushort_t port,
@@ -1012,6 +997,7 @@ static int keyboard_write_output(ushort_t port,
                                 struct vm_device * dev)
 {
     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+    int ret = 0;
 
     if (length != 1) { 
        PrintError("keyboard: write of 60h with >1 byte\n");
@@ -1022,6 +1008,8 @@ static int keyboard_write_output(ushort_t port,
   
     PrintDebug("keyboard: output 0x%x on 60h\n", data);
 
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+
     switch (state->state) {
        case WRITING_CMD_BYTE:
            state->cmd_byte = data;
@@ -1039,7 +1027,9 @@ static int keyboard_write_output(ushort_t port,
            PrintDebug("keyboard: injected key 0x%x\n", data);
            break;
        case INJECTING_MOUSE:
-           PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
+           PushToOutputQueue(dev, data, OVERWRITE, DATA, MOUSE);
+           //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
+           PrintDebug("keyboard: injected mouse event 0x%x\n", data);
            state->state = NORMAL;
            break;
        case IN_MOUSE:
@@ -1059,6 +1049,17 @@ static int keyboard_write_output(ushort_t port,
                PrintDebug("keyboard: done with password\n");
            }
            break;
+       case SET_LEDS:
+           PrintDebug("Keyboard: LEDs being set...\n");
+           PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
+           state->state = NORMAL;
+           break;
+       case SET_RATE:
+           PrintDebug("Keyboard: Rate being set...\n");
+           PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
+           state->state = NORMAL;
+           break;
+       default:
        case NORMAL:
            {
                // command is being sent to keyboard controller
@@ -1074,7 +1075,23 @@ static int keyboard_write_output(ushort_t port,
                        PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
                        // should do something here... PAD
                        state->state = NORMAL;
-                       PrintDebug("keyboard: %s scanning done and acked\n",data==0xf5 ? "disable" : "enable");
+                       PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
+                       break;
+                   case 0xf3:
+                       PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
+                       state->state = SET_RATE;
+                       break;
+                   case 0xf2: // get keyboard ID
+                       PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
+                       state->state = KBD_ID1;
+                       PrintDebug("Keyboard: Requesting Keyboard ID\n");
+
+                       //PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
+                       //state->state = KBD_ID2;
+                       break;
+                   case 0xed: // enable keyboard LEDs
+                       PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
+                       state->state = SET_LEDS;
                        break;
                    case 0xfe: // resend
                    case 0xfd: // set key type make
@@ -1085,21 +1102,29 @@ static int keyboard_write_output(ushort_t port,
                    case 0xf8: // set all make/break
                    case 0xf7: // set all typemaktic
                    case 0xf6: // set defaults
-                   case 0xf3: // set typematic delay/rate
-                       PrintDebug("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
+                       PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
+
+                       ret = -1;
                        break;
                    default:
-                       PrintDebug("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
+                       PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
                        state->status_byte |= 0x1;
+
+                       ret = -1;
                        break;
                }
                break;
            }
-       default:
-           PrintDebug("keyboard: unknown state %x on command 0x%x on output buffer (60h)\n", state->state, data);
+
     }
   
-    return 1;
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
+
+    if (ret == -1) {
+       return -1;
+    }
+
+    return length;
 }
 
 static int keyboard_read_input(ushort_t port,
@@ -1107,40 +1132,53 @@ static int keyboard_read_input(ushort_t port,
                               uint_t length,
                               struct vm_device * dev)
 {
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
-    if (length == 1) { 
-       uchar_t data;
-       int done_mouse;
+    uchar_t data;
+    int done_mouse;
+    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+    
+    if (length != 1) {
+       PrintError("keyboard: unknown size read from input (60h)\n");
+       return -1;
+    }
+    
+    PrintDebug("keyboard: read from input (60h): ");
 
-       PrintDebug("keyboard: read from input (60h): ");
+    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
 
-       if (state->state == IN_MOUSE) { 
-           done_mouse = mouse_read_input(dev);
-           if (done_mouse) { 
-               state->state = NORMAL;
-           }
-       } 
-      
-       PullFromOutputQueue(dev, &data);
-      
-       if (state->state == RESET) { 
-           // We just delivered the ack for the reset
-           // now we will ready ourselves to deliver the BAT code (success)
-           PushToOutputQueue(dev, 0xaa, OVERWRITE, COMMAND, KEYBOARD);
+    if (state->state == IN_MOUSE) { 
+       done_mouse = mouse_read_input(dev);
+       if (done_mouse) { 
            state->state = NORMAL;
-           PrintDebug(" (in reset, pushing BAT test code 0xaa) ");
        }
+    } 
       
-       PrintDebug("0x%x\n", data);
-
-       *((uchar_t*)dest) = data;
-    
-       return 1;
-    } else {
-       PrintError("keyboard: unknown size read from input (60h)\n");
-       return -1;
+    PullFromOutputQueue(dev, &data);
+      
+    if (state->state == RESET) { 
+       // We just delivered the ack for the reset
+       // now we will ready ourselves to deliver the BAT code (success)
+       PushToOutputQueue(dev, 0xaa, OVERWRITE, COMMAND, KEYBOARD);
+       state->state = NORMAL;
+       PrintDebug(" (in reset, pushing BAT test code 0xaa) ");
+    } else if (state->state == KBD_ID1) {
+       PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
+       state->state = KBD_ID2;
+       PrintDebug(" (in kbd id request, pushing 1st ID val) ");
+    } else if (state->state == KBD_ID2) {
+       PushToOutputQueue(dev, 0x83, OVERWRITE, COMMAND, KEYBOARD);
+       state->state = NORMAL;
+       PrintDebug(" (in kbd id request, pushing 2nd ID val) ");
     }
+
+    v3_unlock_irqrestore(state->kb_lock, irq_state);
+
+    PrintDebug("0x%x\n", data);
+
+    *((uchar_t*)dest) = data;
+
+    return length;
+
 }
 
 
@@ -1150,14 +1188,16 @@ static int keyboard_read_input(ushort_t port,
 static int keyboard_init_device(struct vm_device * dev) 
 {
  
-    //  struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
+    struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
 
     PrintDebug("keyboard: init_device\n");
 
-    // Would read state here
-
     keyboard_reset_device(dev);
 
+
+    v3_lock_init(&(data->kb_lock));
+
+
     // hook ports
     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);