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