* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
*/
-#include <devices/8254.h>
+
#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_time.h>
#include <palacios/vmm_util.h>
#include <palacios/vmm_intr.h>
+#include <palacios/vmm_config.h>
+#include <palacios/vmm_io.h>
-
-#ifndef DEBUG_PIT
+#ifndef CONFIG_DEBUG_PIT
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
#define CHANNEL1_PORT 0x41
#define CHANNEL2_PORT 0x42
#define COMMAND_PORT 0x43
+#define SPEAKER_PORT 0x61
#define PIT_INTR_NUM 0
+#define PIT_SPEAKER_GATE 0x01
/* The order of these typedefs is important because the numerical values correspond to the
* values coming from the io ports
ullong_t pit_counter;
ullong_t pit_reload;
+ struct v3_timer * timer;
+
+ struct v3_vm_info * vm;
struct channel ch_0;
struct channel ch_1;
struct channel ch_2;
+ uint8_t speaker;
};
* This should call out to handle_SQR_WAVE_tics, etc...
*/
// Returns true if the the output signal changed state
-static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint_t oscillations) {
+static int handle_crystal_tics(struct pit * pit, struct channel * ch, uint_t oscillations) {
uint_t channel_cycles = 0;
uint_t output_changed = 0;
} else {
ushort_t reload_val = ch->reload_value;
- // TODO: Check this....
- // Is this correct???
- if (reload_val == 0) {
- reload_val = 1;
+ if (ch->op_mode == SW_STROBE) {
+ reload_val = 0xffff;
}
oscillations -= ch->counter;
reload_val -= reload_val % 2;
}
+ // TODO: Check this....
+ // Is this correct???
+ if (reload_val == 0) {
+ reload_val = 1;
+ }
+
channel_cycles += oscillations / reload_val;
oscillations = oscillations % reload_val;
break;
case SW_STROBE:
- PrintError("Software strobe not implemented\n");
- return -1;
+
+ if (channel_cycles > 0) {
+ if (ch->output_pin == 1) {
+ ch->output_pin = 0;
+ output_changed = 1;
+ }
+ }
break;
case HW_STROBE:
PrintError("Hardware strobe not implemented\n");
}
+#include <palacios/vm_guest.h>
-static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct pit * state = (struct pit *)dev->private_data;
+static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
+ struct pit * state = (struct pit *)private_data;
// ullong_t tmp_ctr = state->pit_counter;
ullong_t tmp_cycles;
uint_t oscillations = 0;
// update counter with remainder (mod reload)
state->pit_counter = state->pit_reload - cpu_cycles;
- //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
- if (handle_crystal_tics(dev, &(state->ch_0), oscillations) == 1) {
+ if (oscillations) {
+ PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+ }
+
+ if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
// raise interrupt
- PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
- v3_raise_irq(dev->vm, 0);
+ // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
+ v3_raise_irq(info->vm_info, 0);
}
- //handle_crystal_tics(dev, &(state->ch_1), oscillations);
- //handle_crystal_tics(dev, &(state->ch_2), oscillations);
+ //handle_crystal_tics(state, &(state->ch_1), oscillations);
+ handle_crystal_tics(state, &(state->ch_2), oscillations);
}
return;
}
-
-
/* This should call out to handle_SQR_WAVE_write, etc...
*/
static int handle_channel_write(struct channel * ch, char val) {
case SQR_WAVE:
ch->output_pin = 1;
break;
+ case SW_STROBE:
+ ch->output_pin = 1;
+ break;
default:
PrintError("Invalid OP_MODE: %d\n", ch->op_mode);
return -1;
}
+static int handle_speaker_read(uint8_t *speaker, struct channel * ch, char * val) {
+ *val = *speaker;
+ if ((*speaker & PIT_SPEAKER_GATE)) {
+ *val |= (ch->output_pin << 5);
+ }
+
+ return 0;
+}
-
+static int handle_speaker_write(uint8_t *speaker, struct channel * ch, char val) {
+ *speaker = (val & ~0x20);
+ return 0;
+}
static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
ch->op_mode = cmd.op_mode;
case SQR_WAVE:
ch->output_pin = 1;
break;
+ case SW_STROBE:
+ ch->output_pin = 1;
+ break;
default:
PrintError("Invalid OP_MODE: %d\n", cmd.op_mode);
return -1;
-static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct pit * state = (struct pit *)dev->private_data;
+static int pit_read_channel(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
+ struct pit * state = (struct pit *)priv_data;
char * val = (char *)dst;
if (length != 1) {
return -1;
}
break;
+ case SPEAKER_PORT:
+ if (handle_speaker_read(&state->speaker, &(state->ch_2), val) == -1) {
+ PrintError("SPEAKER read error\n");
+ return -1;
+ }
+ break;
default:
PrintError("8254 PIT: Read from invalid port (%d)\n", port);
return -1;
-static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct pit * state = (struct pit *)dev->private_data;
+static int pit_write_channel(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+ struct pit * state = (struct pit *)priv_data;
char val = *(char *)src;
if (length != 1) {
return -1;
}
break;
+ case SPEAKER_PORT:
+ if (handle_speaker_write(&state->speaker, &(state->ch_2), val) == -1) {
+ PrintError("SPEAKER write error\n");
+ return -1;
+ }
+ break;
default:
PrintError("8254 PIT: Write to invalid port (%d)\n", port);
return -1;
-static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct pit * state = (struct pit *)dev->private_data;
+static int pit_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+ struct pit * state = (struct pit *)priv_data;
struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
PrintDebug("8254 PIT: Write to PIT Command port\n");
-static struct vm_timer_ops timer_ops = {
- .update_time = pit_update_time,
+static struct v3_timer_ops timer_ops = {
+ .update_timer = pit_update_timer,
};
}
-static int pit_init(struct vm_device * dev) {
- struct pit * state = (struct pit *)dev->private_data;
+
+
+static int pit_free(void * private_data) {
+ struct pit * state = (struct pit *)private_data;
+ struct guest_info * info = &(state->vm->cores[0]);
+
+
+ if (state->timer) {
+ v3_remove_timer(info, state->timer);
+ }
+
+ V3_Free(state);
+ return 0;
+}
+
+
+static struct v3_device_ops dev_ops = {
+ .free = (int (*)(void *))pit_free,
+
+
+};
+
+#include <palacios/vm_guest.h>
+
+static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+ struct pit * pit_state = NULL;
+ struct vm_device * dev = NULL;
+ char * dev_id = v3_cfg_val(cfg, "ID");
+ int ret = 0;
+
+ // PIT is only usable in non-multicore environments
+ // just hardcode the core context
+ struct guest_info * info = &(vm->cores[0]);
+
uint_t cpu_khz = V3_CPU_KHZ();
ullong_t reload_val = (ullong_t)cpu_khz * 1000;
- 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);
+ pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
+
+ V3_ASSERT(pit_state != NULL);
+ pit_state->speaker = 0;
+ pit_state->vm = vm;
+
+ dev = v3_add_device(vm, dev_id, &dev_ops, pit_state);
-#ifdef DEBUG_PIT
+ if (dev == NULL) {
+ PrintError("Could not attach device %s\n", dev_id);
+ V3_Free(pit_state);
+ return -1;
+ }
+
+ ret |= v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
+ ret |= v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
+ ret |= v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
+ ret |= v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
+ ret |= v3_dev_hook_io(dev, SPEAKER_PORT, &pit_read_channel, &pit_write_channel);
+
+ if (ret != 0) {
+ PrintError("8254 PIT: Failed to hook IO ports\n");
+ v3_remove_device(dev);
+ return -1;
+ }
+
+#ifdef CONFIG_DEBUG_PIT
PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
- PrintTraceLL(reload_val);
+ //PrintTrace(reload_val);
PrintDebug("\n");
#endif
- v3_add_timer(dev->vm, &timer_ops, dev);
+
+
+ pit_state->timer = v3_add_timer(info, &timer_ops, pit_state);
+
+ if (pit_state->timer == NULL) {
+ v3_remove_device(dev);
+ return -1;
+ }
// Get cpu frequency and calculate the global pit oscilattor counter/cycle
do_divll(reload_val, OSC_HZ);
- state->pit_counter = reload_val;
- state->pit_reload = reload_val;
-
+ pit_state->pit_counter = reload_val;
+ pit_state->pit_reload = reload_val;
- init_channel(&(state->ch_0));
- init_channel(&(state->ch_1));
- init_channel(&(state->ch_2));
+ init_channel(&(pit_state->ch_0));
+ init_channel(&(pit_state->ch_1));
+ init_channel(&(pit_state->ch_2));
-#ifdef DEBUG_PIT
+#ifdef CONFIG_DEBUG_PIT
PrintDebug("8254 PIT: CPU MHZ=%d -- pit count=", cpu_khz / 1000);
- PrintTraceLL(state->pit_counter);
+ //PrintTraceLL(pit_state->pit_counter);
PrintDebug("\n");
#endif
return 0;
}
-static int pit_deinit(struct vm_device * dev) {
-
- return 0;
-}
-
-
-static struct vm_device_ops dev_ops = {
- .init = pit_init,
- .deinit = pit_deinit,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-
-};
-
-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 = v3_create_device("PIT", &dev_ops, pit_state);
-
- return dev;
-}
+device_register("8254_PIT", pit_init);