some ifdef --> if fixes
[coreboot.git] / src / devices / oprom / yabel / mem.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  * All rights reserved.
5  * This program and the accompanying materials
6  * are made available under the terms of the BSD License
7  * which accompanies this distribution, and is available at
8  * http://www.opensource.org/licenses/bsd-license.php
9  *
10  * Contributors:
11  *     IBM Corporation - initial implementation
12  *****************************************************************************/
13
14 #include <types.h>
15 #include "debug.h"
16 #include "device.h"
17 #include "x86emu/x86emu.h"
18 #include "biosemu.h"
19 #include "mem.h"
20 #include "compat/time.h"
21
22 #if !CONFIG_YABEL_DIRECTHW || !CONFIG_YABEL_DIRECTHW
23
24 #if CONFIG_PCI_OPTION_ROM_RUN_YABEL
25 #include <device/resource.h>
26 #endif
27
28 // define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...)
29 #if CONFIG_X86EMU_DEBUG
30 static u8 in_check = 0; // to avoid recursion...
31
32 static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval)
33 {
34         u16 ebda_segment;
35         u32 ebda_size;
36         if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)))
37                 return;
38         in_check = 1;
39         /* determine ebda_segment and size
40         * since we are using my_rdx calls, make sure, this is after setting in_check! */
41         /* offset 03 in BDA is EBDA segment */
42         ebda_segment = my_rdw(0x40e);
43         /* first value in ebda is size in KB */
44         ebda_size = my_rdb(ebda_segment << 4) * 1024;
45         /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */
46         if (_addr < 0x400) {
47                 DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n",
48                                 __func__, _addr / 4, _rval);
49         }
50         /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/
51         else if ((_addr >= 0x400) && (_addr < 0x500)) {
52                 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n",
53                                 __func__, _addr, _rval);
54                 /* dump registers */
55                 /* x86emu_dump_xregs(); */
56         }
57         /* access to first 64k of memory... */
58         else if (_addr < 0x10000) {
59                 DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n",
60                                 __func__, _addr, _rval);
61                 /* dump registers */
62                 /* x86emu_dump_xregs(); */
63         }
64         /* read from PMM_CONV_SEGMENT */
65         else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) {
66                 DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n",
67                                 __func__, PMM_CONV_SEGMENT, _addr, _rval);
68                 /* HALT_SYS(); */
69                 /* dump registers */
70                 /* x86emu_dump_xregs(); */
71         }
72         /* read from PNP_DATA_SEGMENT */
73         else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) {
74                 DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n",
75                                 __func__, PNP_DATA_SEGMENT, _addr, _rval);
76                 /* HALT_SYS(); */
77                 /* dump registers */
78                 /* x86emu_dump_xregs(); */
79         }
80         /* read from EBDA Segment */
81         else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) {
82                 DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n",
83                                 __func__, ebda_segment, ebda_size, _addr, _rval);
84         }
85         /* read from BIOS_DATA_SEGMENT */
86         else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) {
87                 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n",
88                                 __func__, BIOS_DATA_SEGMENT, _addr, _rval);
89                 /* for PMM debugging */
90                 /*if (_addr == BIOS_DATA_SEGMENT << 4) {
91                         X86EMU_trace_on();
92                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
93                 }*/
94                 /* dump registers */
95                 /* x86emu_dump_xregs(); */
96         }
97         in_check = 0;
98 }
99
100 static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val)
101 {
102         u16 ebda_segment;
103         u32 ebda_size;
104         if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)))
105                 return;
106         in_check = 1;
107         /* determine ebda_segment and size
108          * since we are using my_rdx calls, make sure that this is after
109          * setting in_check! */
110         /* offset 03 in BDA is EBDA segment */
111         ebda_segment = my_rdw(0x40e);
112         /* first value in ebda is size in KB */
113         ebda_size = my_rdb(ebda_segment << 4) * 1024;
114         /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */
115         if (_addr < 0x400) {
116                 DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n",
117                                 __func__, _addr / 4, _val);
118         }
119         /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/
120         else if ((_addr >= 0x400) && (_addr < 0x500)) {
121                 DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n",
122                                         __func__, _addr, _val);
123                 /* dump registers */
124                 /* x86emu_dump_xregs(); */
125         }
126         /* access to first 64k of memory...*/
127         else if (_addr < 0x10000) {
128                 DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n",
129                                 __func__, _addr, _val);
130         /* dump registers */
131                 /* x86emu_dump_xregs(); */
132         }
133         /* write to PMM_CONV_SEGMENT... */
134         else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) {
135                 DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n",
136                                 __func__, PMM_CONV_SEGMENT, _addr, _val);
137                 /* dump registers */
138                 /* x86emu_dump_xregs(); */
139         }
140         /* write to PNP_DATA_SEGMENT... */
141         else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) {
142                 DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n",
143                                 __func__, PNP_DATA_SEGMENT, _addr, _val);
144                 /* dump registers */
145                 /* x86emu_dump_xregs(); */
146         }
147         /* write to EBDA Segment... */
148         else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) {
149                 DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n",
150                                 __func__, ebda_segment, ebda_size, _addr, _val);
151         }
152         /* write to BIOS_DATA_SEGMENT... */
153         else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) {
154                 DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n",
155                                 __func__, BIOS_DATA_SEGMENT, _addr, _val);
156                 /* dump registers */
157                 /* x86emu_dump_xregs(); */
158         }
159         /* write to current CS segment... */
160         else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) {
161                 DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n",
162                                 __func__, M.x86.R_CS, _addr, _val);
163                 /* dump registers */
164                 /* x86emu_dump_xregs(); */
165         }
166         in_check = 0;
167 }
168 #else
169 static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval) {};
170 static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val) {};
171 #endif
172
173 //update time in BIOS Data Area
174 //DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz
175 //byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00
176 //cur_val is the current value, of offset 6c...
177 static void
178 update_time(u32 cur_val)
179 {
180         //for convenience, we let the start of timebase be at midnight, we currently dont support
181         //real daytime anyway...
182         u64 ticks_per_day = tb_freq * 60 * 24;
183         // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second)
184         u32 period_ticks = (55 * tb_freq) / 1000;
185         u64 curr_time = get_time();
186         u64 ticks_since_midnight = curr_time % ticks_per_day;
187         u32 periods_since_midnight = ticks_since_midnight / period_ticks;
188         // if periods since midnight is smaller than last value, set overflow
189         // at BDA Offset 0x70
190         if (periods_since_midnight < cur_val) {
191                 my_wrb(0x470, 1);
192         }
193         // store periods since midnight at BDA offset 0x6c
194         my_wrl(0x46c, periods_since_midnight);
195 }
196
197 // read byte from memory
198 u8
199 my_rdb(u32 addr)
200 {
201         unsigned long translated_addr = addr;
202         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
203         u8 rval;
204         if (translated != 0) {
205                 //translation successfull, access VGA Memory (BAR or Legacy...)
206                 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
207                                  __func__, addr);
208                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
209                 set_ci();
210                 rval = *((u8 *) translated_addr);
211                 clr_ci();
212                 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __func__, addr,
213                                  rval);
214                 return rval;
215         } else if (addr > M.mem_size) {
216                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
217                              __func__, addr);
218                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
219                 HALT_SYS();
220         } else {
221                 /* read from virtual memory */
222                 rval = *((u8 *) (M.mem_base + addr));
223                 DEBUG_CHECK_VMEM_READ(addr, rval);
224                 return rval;
225         }
226         return -1;
227 }
228
229 //read word from memory
230 u16
231 my_rdw(u32 addr)
232 {
233         unsigned long translated_addr = addr;
234         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
235         u16 rval;
236         if (translated != 0) {
237                 //translation successfull, access VGA Memory (BAR or Legacy...)
238                 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
239                                  __func__, addr);
240                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
241                 // check for legacy memory, because of the remapping to BARs, the reads must
242                 // be byte reads...
243                 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
244                         //read bytes a using my_rdb, because of the remapping to BARs
245                         //words may not be contiguous in memory, so we need to translate
246                         //every address...
247                         rval = ((u8) my_rdb(addr)) |
248                             (((u8) my_rdb(addr + 1)) << 8);
249                 } else {
250                         if ((translated_addr & (u64) 0x1) == 0) {
251                                 // 16 bit aligned access...
252                                 set_ci();
253                                 rval = in16le((void *) translated_addr);
254                                 clr_ci();
255                         } else {
256                                 // unaligned access, read single bytes
257                                 set_ci();
258                                 rval = (*((u8 *) translated_addr)) |
259                                     (*((u8 *) translated_addr + 1) << 8);
260                                 clr_ci();
261                         }
262                 }
263                 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __func__, addr,
264                                  rval);
265                 return rval;
266         } else if (addr > M.mem_size) {
267                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
268                              __func__, addr);
269                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
270                 HALT_SYS();
271         } else {
272                 /* read from virtual memory */
273                 rval = in16le((void *) (M.mem_base + addr));
274                 DEBUG_CHECK_VMEM_READ(addr, rval);
275                 return rval;
276         }
277         return -1;
278 }
279
280 //read long from memory
281 u32
282 my_rdl(u32 addr)
283 {
284         unsigned long translated_addr = addr;
285         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
286         u32 rval;
287         if (translated != 0) {
288                 //translation successfull, access VGA Memory (BAR or Legacy...)
289                 DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
290                                  __func__, addr);
291                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
292                 // check for legacy memory, because of the remapping to BARs, the reads must
293                 // be byte reads...
294                 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
295                         //read bytes a using my_rdb, because of the remapping to BARs
296                         //dwords may not be contiguous in memory, so we need to translate
297                         //every address...
298                         rval = ((u8) my_rdb(addr)) |
299                             (((u8) my_rdb(addr + 1)) << 8) |
300                             (((u8) my_rdb(addr + 2)) << 16) |
301                             (((u8) my_rdb(addr + 3)) << 24);
302                 } else {
303                         if ((translated_addr & (u64) 0x3) == 0) {
304                                 // 32 bit aligned access...
305                                 set_ci();
306                                 rval = in32le((void *) translated_addr);
307                                 clr_ci();
308                         } else {
309                                 // unaligned access, read single bytes
310                                 set_ci();
311                                 rval = (*((u8 *) translated_addr)) |
312                                     (*((u8 *) translated_addr + 1) << 8) |
313                                     (*((u8 *) translated_addr + 2) << 16) |
314                                     (*((u8 *) translated_addr + 3) << 24);
315                                 clr_ci();
316                         }
317                 }
318                 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __func__, addr,
319                                  rval);
320                 //HALT_SYS();
321                 return rval;
322         } else if (addr > M.mem_size) {
323                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
324                              __func__, addr);
325                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
326                 HALT_SYS();
327         } else {
328                 /* read from virtual memory */
329                 rval = in32le((void *) (M.mem_base + addr));
330                 switch (addr) {
331                 case 0x46c:
332                         //BDA Time Data, update it, before reading
333                         update_time(rval);
334                         rval = in32le((void *) (M.mem_base + addr));
335                         break;
336                 }
337                 DEBUG_CHECK_VMEM_READ(addr, rval);
338                 return rval;
339         }
340         return -1;
341 }
342
343 //write byte to memory
344 void
345 my_wrb(u32 addr, u8 val)
346 {
347         unsigned long translated_addr = addr;
348         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
349         if (translated != 0) {
350                 //translation successfull, access VGA Memory (BAR or Legacy...)
351                 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
352                                  __func__, addr, val);
353                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
354                 set_ci();
355                 *((u8 *) translated_addr) = val;
356                 clr_ci();
357         } else if (addr > M.mem_size) {
358                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
359                              __func__, addr);
360                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
361                 HALT_SYS();
362         } else {
363                 /* write to virtual memory */
364                 DEBUG_CHECK_VMEM_WRITE(addr, val);
365                 *((u8 *) (M.mem_base + addr)) = val;
366         }
367 }
368
369 void
370 my_wrw(u32 addr, u16 val)
371 {
372         unsigned long translated_addr = addr;
373         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
374         if (translated != 0) {
375                 //translation successfull, access VGA Memory (BAR or Legacy...)
376                 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
377                                  __func__, addr, val);
378                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
379                 // check for legacy memory, because of the remapping to BARs, the reads must
380                 // be byte reads...
381                 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
382                         //read bytes a using my_rdb, because of the remapping to BARs
383                         //words may not be contiguous in memory, so we need to translate
384                         //every address...
385                         my_wrb(addr, (u8) (val & 0x00FF));
386                         my_wrb(addr + 1, (u8) ((val & 0xFF00) >> 8));
387                 } else {
388                         if ((translated_addr & (u64) 0x1) == 0) {
389                                 // 16 bit aligned access...
390                                 set_ci();
391                                 out16le((void *) translated_addr, val);
392                                 clr_ci();
393                         } else {
394                                 // unaligned access, write single bytes
395                                 set_ci();
396                                 *((u8 *) translated_addr) =
397                                     (u8) (val & 0x00FF);
398                                 *((u8 *) translated_addr + 1) =
399                                     (u8) ((val & 0xFF00) >> 8);
400                                 clr_ci();
401                         }
402                 }
403         } else if (addr > M.mem_size) {
404                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
405                              __func__, addr);
406                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
407                 HALT_SYS();
408         } else {
409                 /* write to virtual memory */
410                 DEBUG_CHECK_VMEM_WRITE(addr, val);
411                 out16le((void *) (M.mem_base + addr), val);
412         }
413 }
414 void
415 my_wrl(u32 addr, u32 val)
416 {
417         unsigned long translated_addr = addr;
418         u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
419         if (translated != 0) {
420                 //translation successfull, access VGA Memory (BAR or Legacy...)
421                 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
422                                  __func__, addr, val);
423                 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n",  __func__, addr, translated_addr);
424                 // check for legacy memory, because of the remapping to BARs, the reads must
425                 // be byte reads...
426                 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
427                         //read bytes a using my_rdb, because of the remapping to BARs
428                         //words may not be contiguous in memory, so we need to translate
429                         //every address...
430                         my_wrb(addr, (u8) (val & 0x000000FF));
431                         my_wrb(addr + 1, (u8) ((val & 0x0000FF00) >> 8));
432                         my_wrb(addr + 2, (u8) ((val & 0x00FF0000) >> 16));
433                         my_wrb(addr + 3, (u8) ((val & 0xFF000000) >> 24));
434                 } else {
435                         if ((translated_addr & (u64) 0x3) == 0) {
436                                 // 32 bit aligned access...
437                                 set_ci();
438                                 out32le((void *) translated_addr, val);
439                                 clr_ci();
440                         } else {
441                                 // unaligned access, write single bytes
442                                 set_ci();
443                                 *((u8 *) translated_addr) =
444                                     (u8) (val & 0x000000FF);
445                                 *((u8 *) translated_addr + 1) =
446                                     (u8) ((val & 0x0000FF00) >> 8);
447                                 *((u8 *) translated_addr + 2) =
448                                     (u8) ((val & 0x00FF0000) >> 16);
449                                 *((u8 *) translated_addr + 3) =
450                                     (u8) ((val & 0xFF000000) >> 24);
451                                 clr_ci();
452                         }
453                 }
454         } else if (addr > M.mem_size) {
455                 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
456                              __func__, addr);
457                 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
458                 HALT_SYS();
459         } else {
460                 /* write to virtual memory */
461                 DEBUG_CHECK_VMEM_WRITE(addr, val);
462                 out32le((void *) (M.mem_base + addr), val);
463         }
464 }
465 #else
466 u8
467 my_rdb(u32 addr)
468 {
469         return rdb(addr);
470 }
471
472 u16
473 my_rdw(u32 addr)
474 {
475         return rdw(addr);
476 }
477
478 u32
479 my_rdl(u32 addr)
480 {
481         return rdl(addr);
482 }
483
484 void
485 my_wrb(u32 addr, u8 val)
486 {
487         wrb(addr, val);
488 }
489
490 void
491 my_wrw(u32 addr, u16 val)
492 {
493         wrw(addr, val);
494 }
495
496 void
497 my_wrl(u32 addr, u32 val)
498 {
499         wrl(addr, val);
500 }
501 #endif