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.


*** empty log message ***
[palacios.git] / palacios / src / devices / 8254.c
1 #include <devices/8254.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vmm_time.h>
4
5 // constants
6 #define OSC_HZ 1193182
7
8
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
14
15
16 #define PIT_INTR_NUM 0
17
18 /* The order of these typedefs is important because the numerical values correspond to the 
19  * values coming from the io ports
20  */
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;
24
25
26 struct channel {
27   channel_access_mode_t access_mode;
28   channel_access_state_t access_state;
29
30   channel_op_mode_t op_mode;
31
32
33
34   // Time til interrupt trigger 
35
36   ushort_t counter;
37   ushort_t reload_value;
38
39   uint_t output_pin : 1;
40   uint_t gate_input_pin : 1;
41 };
42
43
44 struct pit {
45
46   ullong_t pit_counter;
47   ullong_t pit_reload;
48
49
50   struct channel ch_0;
51   struct channel ch_1;
52   struct channel ch_2;
53 };
54
55
56 struct pit_cmd_word {
57   uint_t bcd_mode    : 1;
58   uint_t op_mode     : 3;
59   uint_t access_mode : 2;
60   uint_t channel     : 2;
61 };
62
63 struct pit_rdb_cmd_word {
64   uint_t rsvd         : 1; // SBZ
65   uint_t ch_0         : 1;
66   uint_t ch_1         : 1;
67   uint_t ch_2         : 1;
68   uint_t latch_status : 1;
69   uint_t latch_count  : 1;
70   uint_t readback_cmd : 2; // Must Be 0x3
71 };
72
73 struct pit_rdb_status_word {
74   uint_t bcd_mode     : 1;
75   uint_t op_mode      : 3;
76   uint_t access_mode  : 2;
77   uint_t null_count   : 1;
78   uint_t pin_state    : 1; 
79 };
80
81
82
83
84
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);
87   
88   return;
89 }
90
91
92 static int handle_channel_write(struct channel * ch, char val) {
93   //  switch (ch->access_mode) {
94
95
96   //}
97
98
99   return -1;
100 }
101
102
103 static int handle_channel_read(struct channel * ch, char * val) {
104   return -1;
105 }
106
107
108
109
110
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;
114
115   switch (cmd.access_mode) {
116   case LATCH_COUNT:
117     return -1;
118     break;
119   case HIBYTE_ONLY:
120     ch->access_state = WAITING_HIBYTE;
121     break;
122   case LOBYTE_ONLY: 
123   case LOBYTE_HIBYTE:
124     ch->access_state = WAITING_LOBYTE;
125     break;
126   }
127
128
129   switch (cmd.op_mode) {
130   case IRQ_ON_TERM_CNT:
131     ch->output_pin = 0;
132     break;
133   case ONE_SHOT: 
134     ch->output_pin = 1;
135     break;
136   case RATE_GEN: 
137     ch->output_pin = 1;
138     break;
139   default:
140     return -1;
141   }
142
143   return 0;
144     
145 }
146
147
148
149
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;
153
154   if (length != 1) {
155     PrintDebug("8254 PIT: Invalid Read Write length \n");
156     return -1;
157   }
158
159   PrintDebug("8254 PIT: Read of PIT Channel %d\n", port - CHANNEL0_PORT);
160
161   switch (port) {
162   case CHANNEL0_PORT: 
163     if (handle_channel_read(&(state->ch_0), val) == -1) {
164       return -1;
165     }
166     break;
167   case CHANNEL1_PORT:
168     if (handle_channel_read(&(state->ch_1), val) == -1) {
169       return -1;
170     }
171     break;
172   case CHANNEL2_PORT:
173     if (handle_channel_read(&(state->ch_2), val) == -1) {
174       return -1;
175     }
176     break;
177   default:
178     PrintDebug("8254 PIT: Read from invalid port (%d)\n", port);
179     return -1;
180   }
181
182   return length;
183 }
184
185
186
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;
190
191   if (length != 1) {
192     PrintDebug("8254 PIT: Invalid Write Length\n");
193     return -1;
194   }
195
196   PrintDebug("8254 PIT: Write to PIT Channel %d\n", port - CHANNEL0_PORT);
197
198
199   switch (port) {
200   case CHANNEL0_PORT:
201     if (handle_channel_write(&(state->ch_0), val) == -1) {
202       return -1;
203     } 
204     break;
205   case CHANNEL1_PORT:
206     if (handle_channel_write(&(state->ch_1), val) == -1) {
207       return -1;
208     }
209     break;
210   case CHANNEL2_PORT:
211     if (handle_channel_write(&(state->ch_2), val) == -1) {
212       return -1;
213     }
214     break;
215   default:
216     PrintDebug("8254 PIT: Write to invalid port (%d)\n", port);
217     return -1;
218   }
219
220   return length;
221 }
222
223
224
225
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;
229
230   PrintDebug("8254 PIT: Write to PIT Command port\n");
231
232   if (length != 1) {
233     PrintDebug("8254 PIT: Write of Invalid length to command port\n");
234     return -1;
235   }
236
237   switch (cmd->channel) {
238   case 0:
239     if (handle_channel_cmd(&(state->ch_0), *cmd) == -1) {
240       return -1;
241     }
242     break;
243   case 1:
244     if (handle_channel_cmd(&(state->ch_1), *cmd) == -1) {
245       return -1;
246     }
247     break;
248   case 2:
249     if (handle_channel_cmd(&(state->ch_2), *cmd) == -1) {
250       return -1;
251     }
252     break;
253   case 3:
254     // Read Back command
255     return -1;
256     break;
257   default:
258     break;
259   }
260
261
262   return length;
263 }
264
265
266
267
268 static struct vm_timer_ops timer_ops = {
269   .update_time = pit_update_time,
270 };
271
272
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);
278
279
280   v3_add_timer(dev->vm, &timer_ops, dev);
281
282   // Get cpu frequency and calculate the global pit oscilattor counter/cycle
283
284
285   return 0;
286 }
287
288 static int pit_deinit(struct vm_device * dev) {
289
290   return 0;
291 }
292
293
294 static struct vm_device_ops dev_ops = {
295   .init = pit_init,
296   .deinit = pit_deinit,
297   .reset = NULL,
298   .start = NULL,
299   .stop = NULL,
300
301 };
302
303
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);
308
309   struct vm_device * dev = create_device("PIT", &dev_ops, pit_state);
310   
311   return dev;
312 }