|
|
1.1 root 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 "device.h"
16: #include "rtas.h"
17: #include "debug.h"
18: #include "device.h"
19: #include <stdint.h>
20: #include <x86emu/x86emu.h>
21: #include <time.h>
22:
23: // those are defined in net-snk/oflib/pci.c
24: extern unsigned int read_io(void *, size_t);
25: extern int write_io(void *, unsigned int, size_t);
26:
27: //defined in net-snk/kernel/timer.c
28: extern uint64_t get_time(void);
29:
30: // these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
31: // with the functions and struct below
32: void
33: outb(uint8_t val, uint16_t port)
34: {
35: printf("WARNING: outb not implemented!\n");
36: HALT_SYS();
37: }
38:
39: void
40: outw(uint16_t val, uint16_t port)
41: {
42: printf("WARNING: outw not implemented!\n");
43: HALT_SYS();
44: }
45:
46: void
47: outl(uint32_t val, uint16_t port)
48: {
49: printf("WARNING: outl not implemented!\n");
50: HALT_SYS();
51: }
52:
53: uint8_t
54: inb(uint16_t port)
55: {
56: printf("WARNING: inb not implemented!\n");
57: HALT_SYS();
58: return 0;
59: }
60:
61: uint16_t
62: inw(uint16_t port)
63: {
64: printf("WARNING: inw not implemented!\n");
65: HALT_SYS();
66: return 0;
67: }
68:
69: uint32_t
70: inl(uint16_t port)
71: {
72: printf("WARNING: inl not implemented!\n");
73: HALT_SYS();
74: return 0;
75: }
76:
77: uint32_t pci_cfg_read(X86EMU_pioAddr addr, uint8_t size);
78: void pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size);
79: uint8_t handle_port_61h();
80:
81: uint8_t
82: my_inb(X86EMU_pioAddr addr)
83: {
84: uint8_t rval = 0xFF;
85: uint64_t translated_addr = addr;
86: uint8_t translated = dev_translate_address(&translated_addr);
87: if (translated != 0) {
88: //translation successfull, 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: rval = read_io((void *)translated_addr, 1);
93: DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __FUNCTION__,
94: addr, rval);
95: return rval;
96: } else {
97: switch (addr) {
98: case 0x61:
99: //8254 KB Controller / Timer Port
100: rval = handle_port_61h();
101: //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __FUNCTION__, addr, rval);
102: return rval;
103: break;
104: case 0xCFC:
105: case 0xCFD:
106: case 0xCFE:
107: case 0xCFF:
108: // PCI Config Mechanism 1 Ports
109: return (uint8_t) pci_cfg_read(addr, 1);
110: break;
111: case 0x0a:
112: CHECK_DBG(DEBUG_INTR) {
113: X86EMU_trace_on();
114: }
115: M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
116: //HALT_SYS();
117: // no break, intentional fall-through to default!!
118: default:
119: DEBUG_PRINTF_IO
120: ("%s(%04x) reading from bios_device.io_buffer\n",
121: __FUNCTION__, addr);
122: rval = *((uint8_t *) (bios_device.io_buffer + addr));
123: DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
124: __FUNCTION__, addr, rval);
125: return rval;
126: break;
127: }
128: }
129: }
130:
131: uint16_t
132: my_inw(X86EMU_pioAddr addr)
133: {
134: uint64_t translated_addr = addr;
135: uint8_t translated = dev_translate_address(&translated_addr);
136: if (translated != 0) {
137: //translation successfull, access Device I/O (BAR or Legacy...)
138: DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
139: addr);
140: //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
141: uint16_t rval;
142: if ((translated_addr & (uint64_t) 0x1) == 0) {
143: // 16 bit aligned access...
144: uint16_t tempval = read_io((void *)translated_addr, 2);
145: //little endian conversion
146: rval = in16le((void *) &tempval);
147: } else {
148: // unaligned access, read single bytes, little-endian
149: rval = (read_io((void *)translated_addr, 1) << 8)
150: | (read_io((void *)(translated_addr + 1), 1));
151: }
152: DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__,
153: addr, rval);
154: return rval;
155: } else {
156: switch (addr) {
157: case 0xCFC:
158: case 0xCFE:
159: //PCI Config Mechanism 1
160: return (uint16_t) pci_cfg_read(addr, 2);
161: break;
162: default:
163: DEBUG_PRINTF_IO
164: ("%s(%04x) reading from bios_device.io_buffer\n",
165: __FUNCTION__, addr);
166: uint16_t rval =
167: in16le((void *) bios_device.io_buffer + addr);
168: DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
169: __FUNCTION__, addr, rval);
170: return rval;
171: break;
172: }
173: }
174: }
175:
176: uint32_t
177: my_inl(X86EMU_pioAddr addr)
178: {
179: uint64_t translated_addr = addr;
180: uint8_t translated = dev_translate_address(&translated_addr);
181: if (translated != 0) {
182: //translation successfull, access Device I/O (BAR or Legacy...)
183: DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__,
184: addr);
185: //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
186: uint32_t rval;
187: if ((translated_addr & (uint64_t) 0x3) == 0) {
188: // 32 bit aligned access...
189: uint32_t tempval = read_io((void *) translated_addr, 4);
190: //little endian conversion
191: rval = in32le((void *) &tempval);
192: } else {
193: // unaligned access, read single bytes, little-endian
194: rval = (read_io((void *)(translated_addr), 1) << 24)
195: | (read_io((void *)(translated_addr + 1), 1) << 16)
196: | (read_io((void *)(translated_addr + 2), 1) << 8)
197: | (read_io((void *)(translated_addr + 3), 1));
198: }
199: DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__,
200: addr, rval);
201: return rval;
202: } else {
203: switch (addr) {
204: case 0xCFC:
205: //PCI Config Mechanism 1
206: return pci_cfg_read(addr, 4);
207: break;
208: default:
209: DEBUG_PRINTF_IO
210: ("%s(%04x) reading from bios_device.io_buffer\n",
211: __FUNCTION__, addr);
212: uint32_t rval =
213: in32le((void *) bios_device.io_buffer + addr);
214: DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
215: __FUNCTION__, addr, rval);
216: return rval;
217: break;
218: }
219: }
220: }
221:
222: void
223: my_outb(X86EMU_pioAddr addr, uint8_t val)
224: {
225: uint64_t translated_addr = addr;
226: uint8_t translated = dev_translate_address(&translated_addr);
227: if (translated != 0) {
228: //translation successfull, access Device I/O (BAR or Legacy...)
229: DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
230: __FUNCTION__, addr, val);
231: //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
232: write_io((void *) translated_addr, val, 1);
233: DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __FUNCTION__,
234: addr, val);
235: } else {
236: switch (addr) {
237: case 0xCFC:
238: case 0xCFD:
239: case 0xCFE:
240: case 0xCFF:
241: // PCI Config Mechanism 1 Ports
242: pci_cfg_write(addr, val, 1);
243: break;
244: default:
245: DEBUG_PRINTF_IO
246: ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
247: __FUNCTION__, addr, val);
248: *((uint8_t *) (bios_device.io_buffer + addr)) = val;
249: break;
250: }
251: }
252: }
253:
254: void
255: my_outw(X86EMU_pioAddr addr, uint16_t val)
256: {
257: uint64_t translated_addr = addr;
258: uint8_t translated = dev_translate_address(&translated_addr);
259: if (translated != 0) {
260: //translation successfull, access Device I/O (BAR or Legacy...)
261: DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
262: __FUNCTION__, addr, val);
263: //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
264: if ((translated_addr & (uint64_t) 0x1) == 0) {
265: // little-endian conversion
266: uint16_t tempval = in16le((void *) &val);
267: // 16 bit aligned access...
268: write_io((void *) translated_addr, tempval, 2);
269: } else {
270: // unaligned access, write single bytes, little-endian
271: write_io(((void *) (translated_addr + 1)),
272: (uint8_t) ((val & 0xFF00) >> 8), 1);
273: write_io(((void *) translated_addr),
274: (uint8_t) (val & 0x00FF), 1);
275: }
276: DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__,
277: addr, val);
278: } else {
279: switch (addr) {
280: case 0xCFC:
281: case 0xCFE:
282: // PCI Config Mechanism 1 Ports
283: pci_cfg_write(addr, val, 2);
284: break;
285: default:
286: DEBUG_PRINTF_IO
287: ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
288: __FUNCTION__, addr, val);
289: out16le((void *) bios_device.io_buffer + addr, val);
290: break;
291: }
292: }
293: }
294:
295: void
296: my_outl(X86EMU_pioAddr addr, uint32_t val)
297: {
298: uint64_t translated_addr = addr;
299: uint8_t translated = dev_translate_address(&translated_addr);
300: if (translated != 0) {
301: //translation successfull, access Device I/O (BAR or Legacy...)
302: DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
303: __FUNCTION__, addr, val);
304: //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
305: if ((translated_addr & (uint64_t) 0x3) == 0) {
306: // little-endian conversion
307: uint32_t tempval = in32le((void *) &val);
308: // 32 bit aligned access...
309: write_io((void *) translated_addr, tempval, 4);
310: } else {
311: // unaligned access, write single bytes, little-endian
312: write_io(((void *) translated_addr + 3),
313: (uint8_t) ((val & 0xFF000000) >> 24), 1);
314: write_io(((void *) translated_addr + 2),
315: (uint8_t) ((val & 0x00FF0000) >> 16), 1);
316: write_io(((void *) translated_addr + 1),
317: (uint8_t) ((val & 0x0000FF00) >> 8), 1);
318: write_io(((void *) translated_addr),
319: (uint8_t) (val & 0x000000FF), 1);
320: }
321: DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__,
322: addr, val);
323: } else {
324: switch (addr) {
325: case 0xCFC:
326: // PCI Config Mechanism 1 Ports
327: pci_cfg_write(addr, val, 4);
328: break;
329: default:
330: DEBUG_PRINTF_IO
331: ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
332: __FUNCTION__, addr, val);
333: out32le((void *) bios_device.io_buffer + addr, val);
334: break;
335: }
336: }
337: }
338:
339: uint32_t
340: pci_cfg_read(X86EMU_pioAddr addr, uint8_t size)
341: {
342: uint32_t rval = 0xFFFFFFFF;
343: if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
344: // PCI Configuration Mechanism 1 step 1
345: // write to 0xCF8, sets bus, device, function and Config Space offset
346: // later read from 0xCFC-0xCFF returns the value...
347: uint8_t bus, devfn, offs;
348: uint32_t port_cf8_val = my_inl(0xCF8);
349: if ((port_cf8_val & 0x80000000) != 0) {
350: //highest bit enables config space mapping
351: bus = (port_cf8_val & 0x00FF0000) >> 16;
352: devfn = (port_cf8_val & 0x0000FF00) >> 8;
353: offs = (port_cf8_val & 0x000000FF);
354: offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
355: if ((bus != bios_device.bus)
356: || (devfn != bios_device.devfn)) {
357: // fail accesses to any device but ours...
358: printf
359: ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
360: bus, devfn, offs);
361: HALT_SYS();
362: } else {
363: rval =
364: (uint32_t) rtas_pci_config_read(bios_device.
365: puid, size,
366: bus, devfn,
367: offs);
368: DEBUG_PRINTF_IO
369: ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
370: __FUNCTION__, addr, offs, size, rval);
371: }
372: }
373: }
374: return rval;
375: }
376:
377: void
378: pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size)
379: {
380: if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) {
381: // PCI Configuration Mechanism 1 step 1
382: // write to 0xCF8, sets bus, device, function and Config Space offset
383: // later write to 0xCFC-0xCFF sets the value...
384: uint8_t bus, devfn, offs;
385: uint32_t port_cf8_val = my_inl(0xCF8);
386: if ((port_cf8_val & 0x80000000) != 0) {
387: //highest bit enables config space mapping
388: bus = (port_cf8_val & 0x00FF0000) >> 16;
389: devfn = (port_cf8_val & 0x0000FF00) >> 8;
390: offs = (port_cf8_val & 0x000000FF);
391: offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
392: if ((bus != bios_device.bus)
393: || (devfn != bios_device.devfn)) {
394: // fail accesses to any device but ours...
395: printf
396: ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
397: bus, devfn, offs);
398: HALT_SYS();
399: } else {
400: rtas_pci_config_write(bios_device.puid,
401: size, bus, devfn, offs,
402: val);
403: DEBUG_PRINTF_IO
404: ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
405: __FUNCTION__, addr, offs, size, val);
406: }
407: }
408: }
409: }
410:
411: uint8_t
412: handle_port_61h()
413: {
414: static uint64_t last_time = 0;
415: uint64_t curr_time = get_time();
416: uint64_t time_diff; // time since last call
417: uint32_t period_ticks; // length of a period in ticks
418: uint32_t nr_periods; //number of periods passed since last call
419: // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
420: time_diff = curr_time - last_time;
421: // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
422: // TODO: as long as the frequency does not change, we should not calculate this every time
423: period_ticks = (15 * tb_freq) / 1000000;
424: nr_periods = time_diff / period_ticks;
425: // if the number if ticks passed since last call is odd, we toggle bit 4
426: if ((nr_periods % 2) != 0) {
427: *((uint8_t *) (bios_device.io_buffer + 0x61)) ^= 0x10;
428: }
429: //finally read the value from the io_buffer
430: return *((uint8_t *) (bios_device.io_buffer + 0x61));
431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.