1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
21 #include <x86emu/x86emu.h>
25 //defined in net-snk/kernel/timer.c
26 extern uint64_t get_time(void);
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);
33 my_inb(X86EMU_pioAddr addr)
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__,
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__,
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);
59 // PCI Config Mechanism 1 Ports
60 return (uint8_t) pci_cfg_read(addr, 1);
63 CHECK_DBG(DEBUG_INTR) {
66 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
68 // no break, intentional fall-through to default!!
71 ("%s(%04x) reading from bios_device.io_buffer\n",
73 rval = *((uint8_t *) (bios_device.io_buffer + addr));
74 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
75 __FUNCTION__, addr, rval);
83 my_inw(X86EMU_pioAddr addr)
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__,
91 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
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);
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));
103 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__,
110 //PCI Config Mechanism 1
111 return (uint16_t) pci_cfg_read(addr, 2);
115 ("%s(%04x) reading from bios_device.io_buffer\n",
118 in16le((void *) bios_device.io_buffer + addr);
119 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
120 __FUNCTION__, addr, rval);
128 my_inl(X86EMU_pioAddr addr)
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__,
136 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
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);
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));
150 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__,
156 //PCI Config Mechanism 1
157 return pci_cfg_read(addr, 4);
161 ("%s(%04x) reading from bios_device.io_buffer\n",
164 in32le((void *) bios_device.io_buffer + addr);
165 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
166 __FUNCTION__, addr, rval);
174 my_outb(X86EMU_pioAddr addr, uint8_t val)
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__,
192 // PCI Config Mechanism 1 Ports
193 pci_cfg_write(addr, val, 1);
197 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
198 __FUNCTION__, addr, val);
199 *((uint8_t *) (bios_device.io_buffer + addr)) = val;
206 my_outw(X86EMU_pioAddr addr, uint16_t val)
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);
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);
227 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__,
233 // PCI Config Mechanism 1 Ports
234 pci_cfg_write(addr, val, 2);
238 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
239 __FUNCTION__, addr, val);
240 out16le((void *) bios_device.io_buffer + addr, val);
247 my_outl(X86EMU_pioAddr addr, uint32_t val)
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);
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);
272 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__,
277 // PCI Config Mechanism 1 Ports
278 pci_cfg_write(addr, val, 4);
282 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
283 __FUNCTION__, addr, val);
284 out32le((void *) bios_device.io_buffer + addr, val);
291 pci_cfg_read(X86EMU_pioAddr addr, uint8_t size)
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...
310 ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
315 (uint32_t) rtas_pci_config_read(bios_device.
320 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
321 __FUNCTION__, addr, offs, size, rval);
329 pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size)
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...
347 ("Config access invalid! bus: %x, devfn: %x, offs: %x\n",
351 rtas_pci_config_write(bios_device.puid,
352 size, bus, devfn, offs,
355 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
356 __FUNCTION__, addr, offs, size, val);
363 handle_port_61h(void)
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;
380 //finally read the value from the io_buffer
381 return *((uint8_t *) (bios_device.io_buffer + 0x61));