|
|
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 <stdint.h>
15: #include <cpu.h>
16: #include "debug.h"
17: #include "device.h"
18: #include "x86emu/x86emu.h"
19: #include "biosemu.h"
20: #include <time.h>
21:
22: // define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...)
23: #ifdef DEBUG
24: static uint8_t in_check = 0; // to avoid recursion...
25: uint16_t ebda_segment;
26: uint32_t ebda_size;
27:
28: //TODO: these macros have grown so large, that they should be changed to an inline function,
29: //just for the sake of readability...
30:
31: //declare prototypes of the functions to follow, for use in DEBUG_CHECK_VMEM_ACCESS
32: uint8_t my_rdb(uint32_t);
33: uint16_t my_rdw(uint32_t);
34: uint32_t my_rdl(uint32_t);
35:
36: #define DEBUG_CHECK_VMEM_READ(_addr, _rval) \
37: if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
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: __FUNCTION__, _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: __FUNCTION__, _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: __FUNCTION__, _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: __FUNCTION__, 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: __FUNCTION__, 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: __FUNCTION__, 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: __FUNCTION__, 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: #define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \
100: if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
101: in_check = 1; \
102: /* determine ebda_segment and size \
103: * since we are using my_rdx calls, make sure, this is after setting in_check! */ \
104: /* offset 03 in BDA is EBDA segment */ \
105: ebda_segment = my_rdw(0x40e); \
106: /* first value in ebda is size in KB */ \
107: ebda_size = my_rdb(ebda_segment << 4) * 1024; \
108: /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \
109: if (_addr < 0x400) { \
110: DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \
111: __FUNCTION__, _addr / 4, _val); \
112: } \
113: /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \
114: else if ((_addr >= 0x400) && (addr < 0x500)) { \
115: DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", \
116: __FUNCTION__, _addr, _val); \
117: /* dump registers */ \
118: /* x86emu_dump_xregs(); */ \
119: } \
120: /* access to first 64k of memory...*/ \
121: else if (_addr < 0x10000) { \
122: DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \
123: __FUNCTION__, _addr, _val); \
124: /* dump registers */ \
125: /* x86emu_dump_xregs(); */ \
126: } \
127: /* write to PMM_CONV_SEGMENT... */ \
128: else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
129: DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", \
130: __FUNCTION__, PMM_CONV_SEGMENT, _addr, _val); \
131: /* dump registers */ \
132: /* x86emu_dump_xregs(); */ \
133: } \
134: /* write to PNP_DATA_SEGMENT... */ \
135: else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
136: DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", \
137: __FUNCTION__, PNP_DATA_SEGMENT, _addr, _val); \
138: /* dump registers */ \
139: /* x86emu_dump_xregs(); */ \
140: } \
141: /* write to EBDA Segment... */ \
142: else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
143: DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", \
144: __FUNCTION__, ebda_segment, ebda_size, _addr, _val); \
145: } \
146: /* write to BIOS_DATA_SEGMENT... */ \
147: else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
148: DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", \
149: __FUNCTION__, BIOS_DATA_SEGMENT, _addr, _val); \
150: /* dump registers */ \
151: /* x86emu_dump_xregs(); */ \
152: } \
153: /* write to current CS segment... */ \
154: else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { \
155: DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", \
156: __FUNCTION__, M.x86.R_CS, _addr, _val); \
157: /* dump registers */ \
158: /* x86emu_dump_xregs(); */ \
159: } \
160: in_check = 0; \
161: }
162: #else
163: #define DEBUG_CHECK_VMEM_READ(_addr, _rval)
164: #define DEBUG_CHECK_VMEM_WRITE(_addr, _val)
165: #endif
166:
167: //defined in net-snk/kernel/timer.c
168: extern uint64_t get_time(void);
169:
170: void update_time(uint32_t);
171:
172: // read byte from memory
173: uint8_t
174: my_rdb(uint32_t addr)
175: {
176: uint64_t translated_addr = addr;
177: uint8_t translated = dev_translate_address(&translated_addr);
178: uint8_t rval;
179: if (translated != 0) {
180: //translation successfull, access VGA Memory (BAR or Legacy...)
181: DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
182: __FUNCTION__, addr);
183: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
184: set_ci();
185: rval = *((uint8_t *) translated_addr);
186: clr_ci();
187: DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __FUNCTION__, addr,
188: rval);
189: return rval;
190: } else if (addr > M.mem_size) {
191: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
192: __FUNCTION__, addr);
193: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
194: HALT_SYS();
195: } else {
196: /* read from virtual memory */
197: rval = *((uint8_t *) (M.mem_base + addr));
198: DEBUG_CHECK_VMEM_READ(addr, rval);
199: return rval;
200: }
201: return -1;
202: }
203:
204: //read word from memory
205: uint16_t
206: my_rdw(uint32_t addr)
207: {
208: uint64_t translated_addr = addr;
209: uint8_t translated = dev_translate_address(&translated_addr);
210: uint16_t rval;
211: if (translated != 0) {
212: //translation successfull, access VGA Memory (BAR or Legacy...)
213: DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
214: __FUNCTION__, addr);
215: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
216: // check for legacy memory, because of the remapping to BARs, the reads must
217: // be byte reads...
218: if ((addr >= 0xa0000) && (addr < 0xc0000)) {
219: //read bytes a using my_rdb, because of the remapping to BARs
220: //words may not be contiguous in memory, so we need to translate
221: //every address...
222: rval = ((uint8_t) my_rdb(addr)) |
223: (((uint8_t) my_rdb(addr + 1)) << 8);
224: } else {
225: if ((translated_addr & (uint64_t) 0x1) == 0) {
226: // 16 bit aligned access...
227: set_ci();
228: rval = in16le((void *) translated_addr);
229: clr_ci();
230: } else {
231: // unaligned access, read single bytes
232: set_ci();
233: rval = (*((uint8_t *) translated_addr)) |
234: (*((uint8_t *) translated_addr + 1) << 8);
235: clr_ci();
236: }
237: }
238: DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __FUNCTION__, addr,
239: rval);
240: return rval;
241: } else if (addr > M.mem_size) {
242: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
243: __FUNCTION__, addr);
244: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
245: HALT_SYS();
246: } else {
247: /* read from virtual memory */
248: rval = in16le((void *) (M.mem_base + addr));
249: DEBUG_CHECK_VMEM_READ(addr, rval);
250: return rval;
251: }
252: return -1;
253: }
254:
255: //read long from memory
256: uint32_t
257: my_rdl(uint32_t addr)
258: {
259: uint64_t translated_addr = addr;
260: uint8_t translated = dev_translate_address(&translated_addr);
261: uint32_t rval;
262: if (translated != 0) {
263: //translation successfull, access VGA Memory (BAR or Legacy...)
264: DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
265: __FUNCTION__, addr);
266: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
267: // check for legacy memory, because of the remapping to BARs, the reads must
268: // be byte reads...
269: if ((addr >= 0xa0000) && (addr < 0xc0000)) {
270: //read bytes a using my_rdb, because of the remapping to BARs
271: //dwords may not be contiguous in memory, so we need to translate
272: //every address...
273: rval = ((uint8_t) my_rdb(addr)) |
274: (((uint8_t) my_rdb(addr + 1)) << 8) |
275: (((uint8_t) my_rdb(addr + 2)) << 16) |
276: (((uint8_t) my_rdb(addr + 3)) << 24);
277: } else {
278: if ((translated_addr & (uint64_t) 0x3) == 0) {
279: // 32 bit aligned access...
280: set_ci();
281: rval = in32le((void *) translated_addr);
282: clr_ci();
283: } else {
284: // unaligned access, read single bytes
285: set_ci();
286: rval = (*((uint8_t *) translated_addr)) |
287: (*((uint8_t *) translated_addr + 1) << 8) |
288: (*((uint8_t *) translated_addr + 2) << 16) |
289: (*((uint8_t *) translated_addr + 3) << 24);
290: clr_ci();
291: }
292: }
293: DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __FUNCTION__, addr,
294: rval);
295: //HALT_SYS();
296: return rval;
297: } else if (addr > M.mem_size) {
298: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
299: __FUNCTION__, addr);
300: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
301: HALT_SYS();
302: } else {
303: /* read from virtual memory */
304: rval = in32le((void *) (M.mem_base + addr));
305: switch (addr) {
306: case 0x46c:
307: //BDA Time Data, update it, before reading
308: update_time(rval);
309: rval = in32le((void *) (M.mem_base + addr));
310: break;
311: }
312: DEBUG_CHECK_VMEM_READ(addr, rval);
313: return rval;
314: }
315: return -1;
316: }
317:
318: //write byte to memory
319: void
320: my_wrb(uint32_t addr, uint8_t val)
321: {
322: uint64_t translated_addr = addr;
323: uint8_t translated = dev_translate_address(&translated_addr);
324: if (translated != 0) {
325: //translation successfull, access VGA Memory (BAR or Legacy...)
326: DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
327: __FUNCTION__, addr, val);
328: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
329: set_ci();
330: *((uint8_t *) translated_addr) = val;
331: clr_ci();
332: } else if (addr > M.mem_size) {
333: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
334: __FUNCTION__, addr);
335: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
336: HALT_SYS();
337: } else {
338: /* write to virtual memory */
339: DEBUG_CHECK_VMEM_WRITE(addr, val);
340: *((uint8_t *) (M.mem_base + addr)) = val;
341: }
342: }
343:
344: void
345: my_wrw(uint32_t addr, uint16_t val)
346: {
347: uint64_t translated_addr = addr;
348: uint8_t translated = dev_translate_address(&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: __FUNCTION__, addr, val);
353: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
354: // check for legacy memory, because of the remapping to BARs, the reads must
355: // be byte reads...
356: if ((addr >= 0xa0000) && (addr < 0xc0000)) {
357: //read bytes a using my_rdb, because of the remapping to BARs
358: //words may not be contiguous in memory, so we need to translate
359: //every address...
360: my_wrb(addr, (uint8_t) (val & 0x00FF));
361: my_wrb(addr + 1, (uint8_t) ((val & 0xFF00) >> 8));
362: } else {
363: if ((translated_addr & (uint64_t) 0x1) == 0) {
364: // 16 bit aligned access...
365: set_ci();
366: out16le((void *) translated_addr, val);
367: clr_ci();
368: } else {
369: // unaligned access, write single bytes
370: set_ci();
371: *((uint8_t *) translated_addr) =
372: (uint8_t) (val & 0x00FF);
373: *((uint8_t *) translated_addr + 1) =
374: (uint8_t) ((val & 0xFF00) >> 8);
375: clr_ci();
376: }
377: }
378: } else if (addr > M.mem_size) {
379: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
380: __FUNCTION__, addr);
381: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
382: HALT_SYS();
383: } else {
384: /* write to virtual memory */
385: DEBUG_CHECK_VMEM_WRITE(addr, val);
386: out16le((void *) (M.mem_base + addr), val);
387: }
388: }
389: void
390: my_wrl(uint32_t addr, uint32_t val)
391: {
392: uint64_t translated_addr = addr;
393: uint8_t translated = dev_translate_address(&translated_addr);
394: if (translated != 0) {
395: //translation successfull, access VGA Memory (BAR or Legacy...)
396: DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
397: __FUNCTION__, addr, val);
398: //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr);
399: // check for legacy memory, because of the remapping to BARs, the reads must
400: // be byte reads...
401: if ((addr >= 0xa0000) && (addr < 0xc0000)) {
402: //read bytes a using my_rdb, because of the remapping to BARs
403: //words may not be contiguous in memory, so we need to translate
404: //every address...
405: my_wrb(addr, (uint8_t) (val & 0x000000FF));
406: my_wrb(addr + 1, (uint8_t) ((val & 0x0000FF00) >> 8));
407: my_wrb(addr + 2, (uint8_t) ((val & 0x00FF0000) >> 16));
408: my_wrb(addr + 3, (uint8_t) ((val & 0xFF000000) >> 24));
409: } else {
410: if ((translated_addr & (uint64_t) 0x3) == 0) {
411: // 32 bit aligned access...
412: set_ci();
413: out32le((void *) translated_addr, val);
414: clr_ci();
415: } else {
416: // unaligned access, write single bytes
417: set_ci();
418: *((uint8_t *) translated_addr) =
419: (uint8_t) (val & 0x000000FF);
420: *((uint8_t *) translated_addr + 1) =
421: (uint8_t) ((val & 0x0000FF00) >> 8);
422: *((uint8_t *) translated_addr + 2) =
423: (uint8_t) ((val & 0x00FF0000) >> 16);
424: *((uint8_t *) translated_addr + 3) =
425: (uint8_t) ((val & 0xFF000000) >> 24);
426: clr_ci();
427: }
428: }
429: } else if (addr > M.mem_size) {
430: DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
431: __FUNCTION__, addr);
432: //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
433: HALT_SYS();
434: } else {
435: /* write to virtual memory */
436: DEBUG_CHECK_VMEM_WRITE(addr, val);
437: out32le((void *) (M.mem_base + addr), val);
438: }
439: }
440:
441: //update time in BIOS Data Area
442: //DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz
443: //byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00
444: //cur_val is the current value, of offset 6c...
445: void
446: update_time(uint32_t cur_val)
447: {
448: //for convenience, we let the start of timebase be at midnight, we currently dont support
449: //real daytime anyway...
450: uint64_t ticks_per_day = tb_freq * 60 * 24;
451: // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second)
452: uint32_t period_ticks = (55 * tb_freq) / 1000;
453: uint64_t curr_time = get_time();
454: uint64_t ticks_since_midnight = curr_time % ticks_per_day;
455: uint32_t periods_since_midnight = ticks_since_midnight / period_ticks;
456: // if periods since midnight is smaller than last value, set overflow
457: // at BDA Offset 0x70
458: if (periods_since_midnight < cur_val) {
459: my_wrb(0x470, 1);
460: }
461: // store periods since midnight at BDA offset 0x6c
462: my_wrl(0x46c, periods_since_midnight);
463: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.