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