Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / biosemu / io.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdio.h>
14 #include <cpu.h>
15 #include <pci.h>
16 #include "device.h"
17 #include "rtas.h"
18 #include "debug.h"
19 #include "device.h"
20 #include <stdint.h>
21 #include <x86emu/x86emu.h>
22 #include <time.h>
23 #include "io.h"
24
25 //defined in net-snk/kernel/timer.c
26 extern uint64_t get_time(void);
27
28 uint32_t pci_cfg_read(X86EMU_pioAddr addr, uint8_t size);
29 void pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size);
30 uint8_t handle_port_61h(void);
31
32 uint8_t
33 my_inb(X86EMU_pioAddr addr)
34 {
35         uint8_t rval = 0xFF;
36         uint64_t translated_addr = addr;
37         uint8_t translated = dev_translate_address(&translated_addr);
38         if (translated != 0) {
39                 //translation successful, access Device I/O (BAR or Legacy...)
40                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
41                                 addr);
42                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
43                 rval = read_io((void *)translated_addr, 1);
44                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __FUNCTION__,
45                                 addr, rval);
46                 return rval;
47         } else {
48                 switch (addr) {
49                 case 0x61:
50                         //8254 KB Controller / Timer Port
51                         rval = handle_port_61h();
52                         //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __FUNCTION__, addr, rval);
53                         return rval;
54                         break;
55                 case 0xCFC:
56                 case 0xCFD:
57                 case 0xCFE:
58                 case 0xCFF:
59                         // PCI Config Mechanism 1 Ports
60                         return (uint8_t) pci_cfg_read(addr, 1);
61                         break;
62                 case 0x0a:
63                         CHECK_DBG(DEBUG_INTR) {
64                                 X86EMU_trace_on();
65                         }
66                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
67                         //HALT_SYS();
68                         // no break, intentional fall-through to default!!
69                 default:
70                         DEBUG_PRINTF_IO
71                             ("%s(%04x) reading from bios_device.io_buffer\n",
72                              __FUNCTION__, addr);
73                         rval = *((uint8_t *) (bios_device.io_buffer + addr));
74                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
75                                         __FUNCTION__, addr, rval);
76                         return rval;
77                         break;
78                 }
79         }
80 }
81
82 uint16_t
83 my_inw(X86EMU_pioAddr addr)
84 {
85         uint64_t translated_addr = addr;
86         uint8_t translated = dev_translate_address(&translated_addr);
87         if (translated != 0) {
88                 //translation successful, access Device I/O (BAR or Legacy...)
89                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
90                                 addr);
91                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
92                 uint16_t rval;
93                 if ((translated_addr & (uint64_t) 0x1) == 0) {
94                         // 16 bit aligned access...
95                         uint16_t tempval = read_io((void *)translated_addr, 2);
96                         //little endian conversion
97                         rval = in16le((void *) &tempval);
98                 } else {
99                         // unaligned access, read single bytes, little-endian
100                         rval = (read_io((void *)translated_addr, 1) << 8)
101                                 | (read_io((void *)(translated_addr + 1), 1));
102                 }
103                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__,
104                                 addr, rval);
105                 return rval;
106         } else {
107                 switch (addr) {
108                 case 0xCFC:
109                 case 0xCFE:
110                         //PCI Config Mechanism 1
111                         return (uint16_t) pci_cfg_read(addr, 2);
112                         break;
113                 default:
114                         DEBUG_PRINTF_IO
115                             ("%s(%04x) reading from bios_device.io_buffer\n",
116                              __FUNCTION__, addr);
117                         uint16_t rval =
118                             in16le((void *) bios_device.io_buffer + addr);
119                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
120                                         __FUNCTION__, addr, rval);
121                         return rval;
122                         break;
123                 }
124         }
125 }
126
127 uint32_t
128 my_inl(X86EMU_pioAddr addr)
129 {
130         uint64_t translated_addr = addr;
131         uint8_t translated = dev_translate_address(&translated_addr);
132         if (translated != 0) {
133                 //translation successful, access Device I/O (BAR or Legacy...)
134                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
135                                 addr);
136                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
137                 uint32_t rval;
138                 if ((translated_addr & (uint64_t) 0x3) == 0) {
139                         // 32 bit aligned access...
140                         uint32_t tempval = read_io((void *) translated_addr, 4);
141                         //little endian conversion
142                         rval = in32le((void *) &tempval);
143                 } else {
144                         // unaligned access, read single bytes, little-endian
145                         rval = (read_io((void *)(translated_addr), 1) << 24)
146                                 | (read_io((void *)(translated_addr + 1), 1) << 16)
147                                 | (read_io((void *)(translated_addr + 2), 1) << 8)
148                                 | (read_io((void *)(translated_addr + 3), 1));
149                 }
150                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__,
151                                 addr, rval);
152                 return rval;
153         } else {
154                 switch (addr) {
155                 case 0xCFC:
156                         //PCI Config Mechanism 1
157                         return pci_cfg_read(addr, 4);
158                         break;
159                 default:
160                         DEBUG_PRINTF_IO
161                             ("%s(%04x) reading from bios_device.io_buffer\n",
162                              __FUNCTION__, addr);
163                         uint32_t rval =
164                             in32le((void *) bios_device.io_buffer + addr);
165                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
166                                         __FUNCTION__, addr, rval);
167                         return rval;
168                         break;
169                 }
170         }
171 }
172
173 void
174 my_outb(X86EMU_pioAddr addr, uint8_t val)
175 {
176         uint64_t translated_addr = addr;
177         uint8_t translated = dev_translate_address(&translated_addr);
178         if (translated != 0) {
179                 //translation successful, access Device I/O (BAR or Legacy...)
180                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
181                                 __FUNCTION__, addr, val);
182                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
183                 write_io((void *) translated_addr, val, 1);
184                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __FUNCTION__,
185                                 addr, val);
186         } else {
187                 switch (addr) {
188                 case 0xCFC:
189                 case 0xCFD:
190                 case 0xCFE:
191                 case 0xCFF:
192                         // PCI Config Mechanism 1 Ports
193                         pci_cfg_write(addr, val, 1);
194                         break;
195                 default:
196                         DEBUG_PRINTF_IO
197                             ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
198                              __FUNCTION__, addr, val);
199                         *((uint8_t *) (bios_device.io_buffer + addr)) = val;
200                         break;
201                 }
202         }
203 }
204
205 void
206 my_outw(X86EMU_pioAddr addr, uint16_t val)
207 {
208         uint64_t translated_addr = addr;
209         uint8_t translated = dev_translate_address(&translated_addr);
210         if (translated != 0) {
211                 //translation successful, access Device I/O (BAR or Legacy...)
212                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
213                                 __FUNCTION__, addr, val);
214                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
215                 if ((translated_addr & (uint64_t) 0x1) == 0) {
216                         // little-endian conversion
217                         uint16_t tempval = in16le((void *) &val);
218                         // 16 bit aligned access...
219                         write_io((void *) translated_addr, tempval, 2);
220                 } else {
221                         // unaligned access, write single bytes, little-endian
222                         write_io(((void *) (translated_addr + 1)),
223                                 (uint8_t) ((val & 0xFF00) >> 8), 1);
224                         write_io(((void *) translated_addr),
225                                 (uint8_t) (val & 0x00FF), 1);
226                 }
227                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__,
228                                 addr, val);
229         } else {
230                 switch (addr) {
231                 case 0xCFC:
232                 case 0xCFE:
233                         // PCI Config Mechanism 1 Ports
234                         pci_cfg_write(addr, val, 2);
235                         break;
236                 default:
237                         DEBUG_PRINTF_IO
238                             ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
239                              __FUNCTION__, addr, val);
240                         out16le((void *) bios_device.io_buffer + addr, val);
241                         break;
242                 }
243         }
244 }
245
246 void
247 my_outl(X86EMU_pioAddr addr, uint32_t val)
248 {
249         uint64_t translated_addr = addr;
250         uint8_t translated = dev_translate_address(&translated_addr);
251         if (translated != 0) {
252                 //translation successful, access Device I/O (BAR or Legacy...)
253                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
254                                 __FUNCTION__, addr, val);
255                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
256                 if ((translated_addr & (uint64_t) 0x3) == 0) {
257                         // little-endian conversion
258                         uint32_t tempval = in32le((void *) &val);
259                         // 32 bit aligned access...
260                         write_io((void *) translated_addr,  tempval, 4);
261                 } else {
262                         // unaligned access, write single bytes, little-endian
263                         write_io(((void *) translated_addr + 3),
264                             (uint8_t) ((val & 0xFF000000) >> 24), 1);
265                         write_io(((void *) translated_addr + 2),
266                             (uint8_t) ((val & 0x00FF0000) >> 16), 1);
267                         write_io(((void *) translated_addr + 1),
268                             (uint8_t) ((val & 0x0000FF00) >> 8), 1);
269                         write_io(((void *) translated_addr),
270                             (uint8_t) (val & 0x000000FF), 1);
271                 }
272                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__,
273                                 addr, val);
274         } else {
275                 switch (addr) {
276                 case 0xCFC:
277                         // PCI Config Mechanism 1 Ports
278                         pci_cfg_write(addr, val, 4);
279                         break;
280                 default:
281                         DEBUG_PRINTF_IO
282                             ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
283                              __FUNCTION__, addr, val);
284                         out32le((void *) bios_device.io_buffer + addr, val);
285                         break;
286                 }
287         }
288 }
289
290 uint32_t
291 pci_cfg_read(X86EMU_pioAddr addr, uint8_t size)
292 {
293         uint32_t rval = 0xFFFFFFFF;
294         if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
295                 // PCI Configuration Mechanism 1 step 1
296                 // write to 0xCF8, sets bus, device, function and Config Space offset
297                 // later read from 0xCFC-0xCFF returns the value...
298                 uint8_t bus, devfn, offs;
299                 uint32_t port_cf8_val = my_inl(0xCF8);
300                 if ((port_cf8_val & 0x80000000) != 0) {
301                         //highest bit enables config space mapping
302                         bus = (port_cf8_val & 0x00FF0000) >> 16;
303                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
304                         offs = (port_cf8_val & 0x000000FF);
305                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
306                         if ((bus != bios_device.bus)
307                             || (devfn != bios_device.devfn)) {
308                                 // fail accesses to any device but ours...
309                                 printf
310                                     ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
311                                      bus, devfn, offs);
312                                 HALT_SYS();
313                         } else {
314                                 rval =
315                                     (uint32_t) rtas_pci_config_read(bios_device.
316                                                                     puid, size,
317                                                                     bus, devfn,
318                                                                     offs);
319                                 DEBUG_PRINTF_IO
320                                     ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
321                                      __FUNCTION__, addr, offs, size, rval);
322                         }
323                 }
324         }
325         return rval;
326 }
327
328 void
329 pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size)
330 {
331         if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
332                 // PCI Configuration Mechanism 1 step 1
333                 // write to 0xCF8, sets bus, device, function and Config Space offset
334                 // later write to 0xCFC-0xCFF sets the value...
335                 uint8_t bus, devfn, offs;
336                 uint32_t port_cf8_val = my_inl(0xCF8);
337                 if ((port_cf8_val & 0x80000000) != 0) {
338                         //highest bit enables config space mapping
339                         bus = (port_cf8_val & 0x00FF0000) >> 16;
340                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
341                         offs = (port_cf8_val & 0x000000FF);
342                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
343                         if ((bus != bios_device.bus)
344                             || (devfn != bios_device.devfn)) {
345                                 // fail accesses to any device but ours...
346                                 printf
347                                     ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
348                                      bus, devfn, offs);
349                                 HALT_SYS();
350                         } else {
351                                 rtas_pci_config_write(bios_device.puid,
352                                                       size, bus, devfn, offs,
353                                                       val);
354                                 DEBUG_PRINTF_IO
355                                     ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
356                                      __FUNCTION__, addr, offs, size, val);
357                         }
358                 }
359         }
360 }
361
362 uint8_t
363 handle_port_61h(void)
364 {
365         static uint64_t last_time = 0;
366         uint64_t curr_time = get_time();
367         uint64_t time_diff;     // time since last call
368         uint32_t period_ticks;  // length of a period in ticks
369         uint32_t nr_periods;    //number of periods passed since last call
370         // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
371         time_diff = curr_time - last_time;
372         // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
373         // TODO: as long as the frequency does not change, we should not calculate this every time
374         period_ticks = (15 * tb_freq) / 1000000;
375         nr_periods = time_diff / period_ticks;
376         // if the number if ticks passed since last call is odd, we toggle bit 4
377         if ((nr_periods % 2) != 0) {
378                 *((uint8_t *) (bios_device.io_buffer + 0x61)) ^= 0x10;
379         }
380         //finally read the value from the io_buffer
381         return *((uint8_t *) (bios_device.io_buffer + 0x61));
382 }