1. Move run_bios prototype to device.h
[coreboot.git] / util / x86emu / yabel / io.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  * All rights reserved.
5  * This program and the accompanying materials
6  * are made available under the terms of the BSD License
7  * which accompanies this distribution, and is available at
8  * http://www.opensource.org/licenses/bsd-license.php
9  *
10  * Contributors:
11  *     IBM Corporation - initial implementation
12  *****************************************************************************/
13
14 #include <types.h>
15 #include "compat/rtas.h"
16 #include "compat/time.h"
17 #include "device.h"
18 #include "debug.h"
19 #include <x86emu/x86emu.h>
20 #include "io.h"
21
22 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
23 #include <device/pci.h>
24 #include <device/pci_ops.h>
25 #endif
26
27 static unsigned int
28 read_io(void *addr, size_t sz)
29 {
30         unsigned int ret;
31         /* since we are using inb instructions, we need the port number as 16bit value */
32         u16 port = (u16)(u32) addr;
33
34         switch (sz) {
35         case 1:
36                 asm volatile ("inb %1, %b0" : "=a"(ret) : "d" (port));
37                 break;
38         case 2:
39                 asm volatile ("inw %1, %w0" : "=a"(ret) : "d" (port));
40                 break;
41         case 4:
42                 asm volatile ("inl %1, %0" : "=a"(ret) : "d" (port));
43                 break;
44         default:
45                 ret = 0;
46         }
47
48         return ret;
49 }
50
51 static int
52 write_io(void *addr, unsigned int value, size_t sz)
53 {
54         u16 port = (u16)(u32) addr;
55         switch (sz) {
56         /* since we are using inb instructions, we need the port number as 16bit value */
57         case 1:
58                 asm volatile ("outb %b0, %1" : : "a"(value), "d" (port));
59                 break;
60         case 2:
61                 asm volatile ("outw %w0, %1" : : "a"(value), "d" (port));
62                 break;
63         case 4:
64                 asm volatile ("outl %0, %1" : : "a"(value), "d" (port));
65                 break;
66         default:
67                 return -1;
68         }
69
70         return 0;
71 }
72
73 #ifdef CONFIG_ARCH_X86
74 #include <arch/io.h>
75 #else
76 // these are not used, only needed for linking,  must be overridden using X86emu_setupPioFuncs
77 // with the functions and struct below
78 void
79 outb(u8 val, u16 port)
80 {
81         printf("WARNING: outb not implemented!\n");
82         HALT_SYS();
83 }
84
85 void
86 outw(u16 val, u16 port)
87 {
88         printf("WARNING: outw not implemented!\n");
89         HALT_SYS();
90 }
91
92 void
93 outl(u32 val, u16 port)
94 {
95         printf("WARNING: outl not implemented!\n");
96         HALT_SYS();
97 }
98
99 u8
100 inb(u16 port)
101 {
102         printf("WARNING: inb not implemented!\n");
103         HALT_SYS();
104         return 0;
105 }
106
107 u16
108 inw(u16 port)
109 {
110         printf("WARNING: inw not implemented!\n");
111         HALT_SYS();
112         return 0;
113 }
114
115 u32
116 inl(u16 port)
117 {
118         printf("WARNING: inl not implemented!\n");
119         HALT_SYS();
120         return 0;
121 }
122 #endif
123
124 #if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
125 u8 my_inb(X86EMU_pioAddr addr)
126 {
127         u8 val;
128
129         val = inb(addr);
130         DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
131
132         return val;
133 }
134
135 u16 my_inw(X86EMU_pioAddr addr)
136 {
137         u16 val;
138
139         val = inw(addr);
140         DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
141
142         return val;
143 }
144
145 u32 my_inl(X86EMU_pioAddr addr)
146 {
147         u32 val;
148
149         val = inl(addr);
150         DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
151
152         return val;
153 }
154
155 void my_outb(X86EMU_pioAddr addr, u8 val)
156 {
157         DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
158         outb(val, addr);
159 }
160
161 void my_outw(X86EMU_pioAddr addr, u16 val)
162 {
163         DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
164         outw(val, addr);
165 }
166
167 void my_outl(X86EMU_pioAddr addr, u32 val)
168 {
169         DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
170         outl(val, addr);
171 }
172
173 #else
174
175 u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
176 void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
177 u8 handle_port_61h(void);
178
179 u8
180 my_inb(X86EMU_pioAddr addr)
181 {
182         u8 rval = 0xFF;
183         unsigned long translated_addr = addr;
184         u8 translated = biosemu_dev_translate_address(&translated_addr);
185         if (translated != 0) {
186                 //translation successfull, access Device I/O (BAR or Legacy...)
187                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
188                                 addr);
189                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
190                 rval = read_io((void *)translated_addr, 1);
191                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
192                                 addr, rval);
193                 return rval;
194         } else {
195                 switch (addr) {
196                 case 0x61:
197                         //8254 KB Controller / Timer Port
198                         // rval = handle_port_61h();
199                         rval = inb(0x61);
200                         //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
201                         return rval;
202                         break;
203                 case 0xCFC:
204                 case 0xCFD:
205                 case 0xCFE:
206                 case 0xCFF:
207                         // PCI Config Mechanism 1 Ports
208                         return (u8) pci_cfg_read(addr, 1);
209                         break;
210                 case 0x0a:
211                         CHECK_DBG(DEBUG_INTR) {
212                                 X86EMU_trace_on();
213                         }
214                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
215                         //HALT_SYS();
216                         // no break, intentional fall-through to default!!
217                 default:
218                         DEBUG_PRINTF_IO
219                             ("%s(%04x) reading from bios_device.io_buffer\n",
220                              __func__, addr);
221                         rval = *((u8 *) (bios_device.io_buffer + addr));
222                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
223                                         __func__, addr, rval);
224                         return rval;
225                         break;
226                 }
227         }
228 }
229
230 u16
231 my_inw(X86EMU_pioAddr addr)
232 {
233         unsigned long translated_addr = addr;
234         u8 translated = biosemu_dev_translate_address(&translated_addr);
235         if (translated != 0) {
236                 //translation successfull, access Device I/O (BAR or Legacy...)
237                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
238                                 addr);
239                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
240                 u16 rval;
241                 if ((translated_addr & (u64) 0x1) == 0) {
242                         // 16 bit aligned access...
243                         u16 tempval = read_io((void *)translated_addr, 2);
244                         //little endian conversion
245                         rval = in16le((void *) &tempval);
246                 } else {
247                         // unaligned access, read single bytes, little-endian
248                         rval = (read_io((void *)translated_addr, 1) << 8)
249                                 | (read_io((void *)(translated_addr + 1), 1));
250                 }
251                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
252                                 addr, rval);
253                 return rval;
254         } else {
255                 switch (addr) {
256                 case 0xCFC:
257                 case 0xCFE:
258                         //PCI Config Mechanism 1
259                         return (u16) pci_cfg_read(addr, 2);
260                         break;
261                 default:
262                         DEBUG_PRINTF_IO
263                             ("%s(%04x) reading from bios_device.io_buffer\n",
264                              __func__, addr);
265                         u16 rval =
266                             in16le((void *) bios_device.io_buffer + addr);
267                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
268                                         __func__, addr, rval);
269                         return rval;
270                         break;
271                 }
272         }
273 }
274
275 u32
276 my_inl(X86EMU_pioAddr addr)
277 {
278         unsigned long translated_addr = addr;
279         u8 translated = biosemu_dev_translate_address(&translated_addr);
280         if (translated != 0) {
281                 //translation successfull, access Device I/O (BAR or Legacy...)
282                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
283                                 addr);
284                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
285                 u32 rval;
286                 if ((translated_addr & (u64) 0x3) == 0) {
287                         // 32 bit aligned access...
288                         u32 tempval = read_io((void *) translated_addr, 4);
289                         //little endian conversion
290                         rval = in32le((void *) &tempval);
291                 } else {
292                         // unaligned access, read single bytes, little-endian
293                         rval = (read_io((void *)(translated_addr), 1) << 24)
294                                 | (read_io((void *)(translated_addr + 1), 1) << 16)
295                                 | (read_io((void *)(translated_addr + 2), 1) << 8)
296                                 | (read_io((void *)(translated_addr + 3), 1));
297                 }
298                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
299                                 addr, rval);
300                 return rval;
301         } else {
302                 switch (addr) {
303                 case 0xCFC:
304                         //PCI Config Mechanism 1
305                         return pci_cfg_read(addr, 4);
306                         break;
307                 default:
308                         DEBUG_PRINTF_IO
309                             ("%s(%04x) reading from bios_device.io_buffer\n",
310                              __func__, addr);
311                         u32 rval =
312                             in32le((void *) bios_device.io_buffer + addr);
313                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
314                                         __func__, addr, rval);
315                         return rval;
316                         break;
317                 }
318         }
319 }
320
321 void
322 my_outb(X86EMU_pioAddr addr, u8 val)
323 {
324         unsigned long translated_addr = addr;
325         u8 translated = biosemu_dev_translate_address(&translated_addr);
326         if (translated != 0) {
327                 //translation successfull, access Device I/O (BAR or Legacy...)
328                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
329                                 __func__, addr, val);
330                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
331                 write_io((void *) translated_addr, val, 1);
332                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
333                                 addr, val);
334         } else {
335                 switch (addr) {
336                 case 0xCFC:
337                 case 0xCFD:
338                 case 0xCFE:
339                 case 0xCFF:
340                         // PCI Config Mechanism 1 Ports
341                         pci_cfg_write(addr, val, 1);
342                         break;
343                 default:
344                         DEBUG_PRINTF_IO
345                             ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
346                              __func__, addr, val);
347                         *((u8 *) (bios_device.io_buffer + addr)) = val;
348                         break;
349                 }
350         }
351 }
352
353 void
354 my_outw(X86EMU_pioAddr addr, u16 val)
355 {
356         unsigned long translated_addr = addr;
357         u8 translated = biosemu_dev_translate_address(&translated_addr);
358         if (translated != 0) {
359                 //translation successfull, access Device I/O (BAR or Legacy...)
360                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
361                                 __func__, addr, val);
362                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
363                 if ((translated_addr & (u64) 0x1) == 0) {
364                         // little-endian conversion
365                         u16 tempval = in16le((void *) &val);
366                         // 16 bit aligned access...
367                         write_io((void *) translated_addr, tempval, 2);
368                 } else {
369                         // unaligned access, write single bytes, little-endian
370                         write_io(((void *) (translated_addr + 1)),
371                                 (u8) ((val & 0xFF00) >> 8), 1);
372                         write_io(((void *) translated_addr),
373                                 (u8) (val & 0x00FF), 1);
374                 }
375                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
376                                 addr, val);
377         } else {
378                 switch (addr) {
379                 case 0xCFC:
380                 case 0xCFE:
381                         // PCI Config Mechanism 1 Ports
382                         pci_cfg_write(addr, val, 2);
383                         break;
384                 default:
385                         DEBUG_PRINTF_IO
386                             ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
387                              __func__, addr, val);
388                         out16le((void *) bios_device.io_buffer + addr, val);
389                         break;
390                 }
391         }
392 }
393
394 void
395 my_outl(X86EMU_pioAddr addr, u32 val)
396 {
397         unsigned long translated_addr = addr;
398         u8 translated = biosemu_dev_translate_address(&translated_addr);
399         if (translated != 0) {
400                 //translation successfull, access Device I/O (BAR or Legacy...)
401                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
402                                 __func__, addr, val);
403                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
404                 if ((translated_addr & (u64) 0x3) == 0) {
405                         // little-endian conversion
406                         u32 tempval = in32le((void *) &val);
407                         // 32 bit aligned access...
408                         write_io((void *) translated_addr,  tempval, 4);
409                 } else {
410                         // unaligned access, write single bytes, little-endian
411                         write_io(((void *) translated_addr + 3),
412                             (u8) ((val & 0xFF000000) >> 24), 1);
413                         write_io(((void *) translated_addr + 2),
414                             (u8) ((val & 0x00FF0000) >> 16), 1);
415                         write_io(((void *) translated_addr + 1),
416                             (u8) ((val & 0x0000FF00) >> 8), 1);
417                         write_io(((void *) translated_addr),
418                             (u8) (val & 0x000000FF), 1);
419                 }
420                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
421                                 addr, val);
422         } else {
423                 switch (addr) {
424                 case 0xCFC:
425                         // PCI Config Mechanism 1 Ports
426                         pci_cfg_write(addr, val, 4);
427                         break;
428                 default:
429                         DEBUG_PRINTF_IO
430                             ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
431                              __func__, addr, val);
432                         out32le((void *) bios_device.io_buffer + addr, val);
433                         break;
434                 }
435         }
436 }
437
438 u32
439 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
440 {
441         u32 rval = 0xFFFFFFFF;
442         struct device * dev;
443         if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
444                 // PCI Configuration Mechanism 1 step 1
445                 // write to 0xCF8, sets bus, device, function and Config Space offset
446                 // later read from 0xCFC-0xCFF returns the value...
447                 u8 bus, devfn, offs;
448                 u32 port_cf8_val = my_inl(0xCF8);
449                 if ((port_cf8_val & 0x80000000) != 0) {
450                         //highest bit enables config space mapping
451                         bus = (port_cf8_val & 0x00FF0000) >> 16;
452                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
453                         offs = (port_cf8_val & 0x000000FF);
454                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
455                         DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
456                                 __func__, bus, devfn, offs);
457 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
458                         dev = dev_find_slot(bus, devfn);
459                         DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
460                                 __func__, dev_path(dev));
461                         if (dev == 0) {
462                                 // fail accesses to non-existent devices...
463 #else
464                         dev = bios_device.dev;
465                         if ((bus != bios_device.bus)
466                              || (devfn != bios_device.devfn)) {
467                                 // fail accesses to any device but ours...
468 #endif
469                                 printf
470                                     ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
471                                      __func__, bus, bios_device.bus, devfn,
472                                      bios_device.devfn, offs);
473                                 SET_FLAG(F_CF);
474                                 HALT_SYS();
475                                 return 0;
476                         } else {
477 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
478                                 switch (size) {
479                                         case 1:
480                                                 rval = pci_read_config8(dev, offs);
481                                                 break;
482                                         case 2:
483                                                 rval = pci_read_config16(dev, offs);
484                                                 break;
485                                         case 4:
486                                                 rval = pci_read_config32(dev, offs);
487                                                 break;
488                                 }
489 #else
490                                 rval =
491                                     (u32) rtas_pci_config_read(bios_device.
492                                                                     puid, size,
493                                                                     bus, devfn,
494                                                                     offs);
495 #endif
496                                 DEBUG_PRINTF_IO
497                                     ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
498                                      __func__, addr, offs, size, rval);
499                         }
500                 }
501         }
502         return rval;
503 }
504
505 void
506 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
507 {
508         if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
509                 // PCI Configuration Mechanism 1 step 1
510                 // write to 0xCF8, sets bus, device, function and Config Space offset
511                 // later write to 0xCFC-0xCFF sets the value...
512                 u8 bus, devfn, offs;
513                 u32 port_cf8_val = my_inl(0xCF8);
514                 if ((port_cf8_val & 0x80000000) != 0) {
515                         //highest bit enables config space mapping
516                         bus = (port_cf8_val & 0x00FF0000) >> 16;
517                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
518                         offs = (port_cf8_val & 0x000000FF);
519                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
520                         if ((bus != bios_device.bus)
521                             || (devfn != bios_device.devfn)) {
522                                 // fail accesses to any device but ours...
523                                 printf
524                                     ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
525                                      bus, devfn >> 3, devfn & 7, offs);
526                                 HALT_SYS();
527                         } else {
528 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
529                                 switch (size) {
530                                         case 1:
531                                                 pci_write_config8(bios_device.dev, offs, val);
532                                                 break;
533                                         case 2:
534                                                 pci_write_config16(bios_device.dev, offs, val);
535                                                 break;
536                                         case 4:
537                                                 pci_write_config32(bios_device.dev, offs, val);
538                                                 break;
539                                 }
540 #else
541                                 rtas_pci_config_write(bios_device.puid,
542                                                       size, bus, devfn, offs,
543                                                       val);
544 #endif
545                                 DEBUG_PRINTF_IO
546                                     ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
547                                      __func__, addr, offs, size, val);
548                         }
549                 }
550         }
551 }
552
553 u8
554 handle_port_61h(void)
555 {
556         static u64 last_time = 0;
557         u64 curr_time = get_time();
558         u64 time_diff;  // time since last call
559         u32 period_ticks;       // length of a period in ticks
560         u32 nr_periods; //number of periods passed since last call
561         // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
562         time_diff = curr_time - last_time;
563         // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
564         // TODO: as long as the frequency does not change, we should not calculate this every time
565         period_ticks = (15 * tb_freq) / 1000000;
566         nr_periods = time_diff / period_ticks;
567         // if the number if ticks passed since last call is odd, we toggle bit 4
568         if ((nr_periods % 2) != 0) {
569                 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
570         }
571         //finally read the value from the io_buffer
572         return *((u8 *) (bios_device.io_buffer + 0x61));
573 }
574 #endif