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;
34 // Time til interrupt trigger
37 ushort_t reload_value;
39 uint_t output_pin : 1;
40 uint_t gate_input_pin : 1;
59 uint_t access_mode : 2;
63 struct pit_rdb_cmd_word {
64 uint_t rsvd : 1; // SBZ
68 uint_t latch_status : 1;
69 uint_t latch_count : 1;
70 uint_t readback_cmd : 2; // Must Be 0x3
73 struct pit_rdb_status_word {
76 uint_t access_mode : 2;
77 uint_t null_count : 1;
85 static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) {
86 PrintDebug("Adding %d cycles\n", cpu_cycles);
92 static int handle_channel_write(struct channel * ch, char val) {
93 // switch (ch->access_mode) {
103 static int handle_channel_read(struct channel * ch, char * val) {
111 static int handle_channel_cmd(struct channel * ch, struct pit_cmd_word cmd) {
112 ch->op_mode = cmd.op_mode;
113 ch->access_mode = cmd.access_mode;
115 switch (cmd.access_mode) {
120 ch->access_state = WAITING_HIBYTE;
124 ch->access_state = WAITING_LOBYTE;
129 switch (cmd.op_mode) {
130 case IRQ_ON_TERM_CNT:
150 static int pit_read_channel(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
151 struct pit * state = (struct pit *)dev->private_data;
152 char * val = (char *)dst;
155 PrintDebug("8254 PIT: Invalid Read Write length \n");
159 PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
163 if (handle_channel_read(&(state->ch_0), val) == -1) {
168 if (handle_channel_read(&(state->ch_1), val) == -1) {
173 if (handle_channel_read(&(state->ch_2), val) == -1) {
178 PrintDebug("8254 PIT: Read from invalid port (%d)\n", port);
187 static int pit_write_channel(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
188 struct pit * state = (struct pit *)dev->private_data;
189 char val = *(char *)src;
192 PrintDebug("8254 PIT: Invalid Write Length\n");
196 PrintDebug("8254 PIT: Write to PIT Channel %d\n", port - CHANNEL0_PORT);
201 if (handle_channel_write(&(state->ch_0), val) == -1) {
206 if (handle_channel_write(&(state->ch_1), val) == -1) {
211 if (handle_channel_write(&(state->ch_2), val) == -1) {
216 PrintDebug("8254 PIT: Write to invalid port (%d)\n", port);
226 static int pit_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
227 struct pit * state = (struct pit *)dev->private_data;
228 struct pit_cmd_word * cmd = (struct pit_cmd_word *)src;
230 PrintDebug("8254 PIT: Write to PIT Command port\n");
233 PrintDebug("8254 PIT: Write of Invalid length to command port\n");
237 switch (cmd->channel) {
239 if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
244 if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
249 if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
268 static struct vm_timer_ops timer_ops = {
269 .update_time = pit_update_time,
273 static int pit_init(struct vm_device * dev) {
274 dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
275 dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
276 dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
277 dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
280 v3_add_timer(dev->vm, &timer_ops, dev);
282 // Get cpu frequency and calculate the global pit oscilattor counter/cycle
288 static int pit_deinit(struct vm_device * dev) {
294 static struct vm_device_ops dev_ops = {
296 .deinit = pit_deinit,
304 struct vm_device * create_pit() {
305 struct pit * pit_state = NULL;
306 pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
307 V3_ASSERT(pit_state != NULL);
309 struct vm_device * dev = create_device("PIT", &dev_ops, pit_state);