#include <palacios/vmm.h>
#include <palacios/vmm_types.h>
+#include <palacios/vmm_lock.h>
+
#ifndef DEBUG_KEYBOARD
#undef PrintDebug
// 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;
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
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 {
}
}
-#if 1
+
//
// pull item from outputqueue
// returns 0 if successful
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;
-
-}
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;
}
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;
}
break;
default:
- return -1;
+ PrintError("Invalid mouse state\n");
+ ret = -1;
break;
}
- return 0;
+
+ v3_unlock_irqrestore(state->kb_lock, irq_state);
+
+ return ret;
}
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");
}
break;
}
- return 1;
+ v3_unlock_irqrestore(state->kb_lock, irq_state);
+ return length;
}
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,
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");
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;
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:
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
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
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,
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;
+
}
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);