~ubuntu-branches/ubuntu/wily/slof/wily

« back to all changes in this revision

Viewing changes to clients/net-snk/app/biosemu/io.c

  • Committer: Package Import Robot
  • Author(s): Aurelien Jarno
  • Date: 2012-09-16 23:05:23 UTC
  • Revision ID: package-import@ubuntu.com-20120916230523-r2ynulqmp2tyu2e5
Tags: upstream-20120217+dfsg
ImportĀ upstreamĀ versionĀ 20120217+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <pci.h>
 
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
}