1 #include <devices/8254.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vmm_time.h>
9 /* The 8254 has three counters and one control port */
10 #define CHANNEL0_PORT 0x40
11 #define CHANNEL1_PORT 0x41
12 #define CHANNEL2_PORT 0x42
13 #define COMMAND_PORT 0x43
16 #define PIT_INTR_NUM 0
18 /* The order of these typedefs is important because the numerical values correspond to the
19 * values coming from the io ports
21 typedef enum {NOT_RUNNING, WAITING_LOBYTE, WAITING_HIBYTE, RUNNING} channel_access_state_t;
22 typedef enum {LATCH_COUNT, LOBYTE_ONLY, HIBYTE_ONLY, LOBYTE_HIBYTE} channel_access_mode_t;
23 typedef enum {IRQ_ON_TERM_CNT, ONE_SHOT, RATE_GEN, SQR_WAVE, SW_STROBE, HW_STROBE} channel_op_mode_t;
27 channel_access_mode_t access_mode;
28 channel_access_state_t access_state;
30 channel_op_mode_t op_mode;
32 // Time til interrupt trigger
49 uint_t access_mode : 2;
59 static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
66 static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
67 PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
73 static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
74 PrintDebug("8254 PIT: Write to PIT Channel %d\n", port - CHANNEL0_PORT);
79 static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
80 struct pit * state = (struct pit *)dev->private_data;
81 struct pit_cmd * cmd = (struct pit_cmd *)src;
83 PrintDebug("8254 PIT: Write to PIT Command port\n");
86 PrintDebug("8254 PIT: Write of Invalid length to command port\n");
90 switch (cmd->channel) {
92 state->ch_0.op_mode = cmd->op_mode;
109 static struct vm_timer_ops timer_ops = {
110 .update_time = pit_update_time,
114 static int pit_init(struct vm_device * dev) {
115 dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
116 dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
117 dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
118 dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
121 v3_add_timer(dev->vm, &timer_ops, dev);
126 static int pit_deinit(struct vm_device * dev) {
132 static struct vm_device_ops dev_ops = {
134 .deinit = pit_deinit,
142 struct vm_device * create_pit() {
143 struct pit * pit_state = NULL;
144 pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
145 V3_ASSERT(pit_state != NULL);
147 struct vm_device * dev = create_device("PIT", &dev_ops, pit_state);