1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <types.h>
15#ifndef CONFIG_COREBOOT_V2
16#include <cpu.h>
17#endif
18#include "debug.h"
19#include "device.h"
20#include "x86emu/x86emu.h"
21#include "biosemu.h"
22#ifdef CONFIG_COREBOOT_V2
23#include "compat/time.h"
24#else
25#include <time.h>
26#endif
27
28
29#ifdef CONFIG_DEBUG
30static u8 in_check = 0;
31u16 ebda_segment;
32u32 ebda_size;
33
34
35
36
37
38u8 my_rdb(u32);
39u16 my_rdw(u32);
40u32 my_rdl(u32);
41
42#define DEBUG_CHECK_VMEM_READ(_addr, _rval) \
43 if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
44 in_check = 1; \
45
46 \
47 \
48 ebda_segment = my_rdw(0x40e); \
49 \
50 ebda_size = my_rdb(ebda_segment << 4) * 1024; \
51 \
52 if (_addr < 0x400) { \
53 DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", \
54 __func__, _addr / 4, _rval); \
55 } \
56 \
57 else if ((_addr >= 0x400) && (addr < 0x500)) { \
58 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", \
59 __func__, _addr, _rval); \
60 \
61 \
62 } \
63 \
64 else if (_addr < 0x10000) { \
65 DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", \
66 __func__, _addr, _rval); \
67 \
68 \
69 } \
70 \
71 else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
72 DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", \
73 __func__, PMM_CONV_SEGMENT, _addr, _rval); \
74 \
75 \
76 \
77 } \
78 \
79 else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
80 DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", \
81 __func__, PNP_DATA_SEGMENT, _addr, _rval); \
82 \
83 \
84 \
85 } \
86 \
87 else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
88 DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", \
89 __func__, ebda_segment, ebda_size, _addr, _rval); \
90 } \
91 \
92 else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
93 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", \
94 __func__, BIOS_DATA_SEGMENT, _addr, _rval); \
95 \
96
97
98
99 \
100 \
101 \
102 } \
103 in_check = 0; \
104 }
105#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \
106 if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
107 in_check = 1; \
108
109 \
110 \
111 ebda_segment = my_rdw(0x40e); \
112 \
113 ebda_size = my_rdb(ebda_segment << 4) * 1024; \
114 \
115 if (_addr < 0x400) { \
116 DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \
117 __func__, _addr / 4, _val); \
118 } \
119 \
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 \
124 \
125 } \
126 \
127 else if (_addr < 0x10000) { \
128 DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \
129 __func__, _addr, _val); \
130 \
131 \
132 } \
133 \
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 \
138 \
139 } \
140 \
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 \
145 \
146 } \
147 \
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 \
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 \
157 \
158 } \
159 \
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 \
164 \
165 } \
166 in_check = 0; \
167 }
168#else
169#define DEBUG_CHECK_VMEM_READ(_addr, _rval)
170#define DEBUG_CHECK_VMEM_WRITE(_addr, _val)
171#endif
172
173
174extern u64 get_time(void);
175
176void update_time(u32);
177
178
179u8
180my_rdb(u32 addr)
181{
182 unsigned long translated_addr = addr;
183 u8 translated = biosemu_dev_translate_address(&translated_addr);
184 u8 rval;
185 if (translated != 0) {
186
187 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
188 __func__, addr);
189
190 set_ci();
191 rval = *((u8 *) translated_addr);
192 clr_ci();
193 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __func__, addr,
194 rval);
195 return rval;
196 } else if (addr > M.mem_size) {
197 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
198 __func__, addr);
199
200 HALT_SYS();
201 } else {
202
203 rval = *((u8 *) (M.mem_base + addr));
204 DEBUG_CHECK_VMEM_READ(addr, rval);
205 return rval;
206 }
207 return -1;
208}
209
210
211u16
212my_rdw(u32 addr)
213{
214 unsigned long translated_addr = addr;
215 u8 translated = biosemu_dev_translate_address(&translated_addr);
216 u16 rval;
217 if (translated != 0) {
218
219 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
220 __func__, addr);
221
222
223
224 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
225
226
227
228 rval = ((u8) my_rdb(addr)) |
229 (((u8) my_rdb(addr + 1)) << 8);
230 } else {
231 if ((translated_addr & (u64) 0x1) == 0) {
232
233 set_ci();
234 rval = in16le((void *) translated_addr);
235 clr_ci();
236 } else {
237
238 set_ci();
239 rval = (*((u8 *) translated_addr)) |
240 (*((u8 *) translated_addr + 1) << 8);
241 clr_ci();
242 }
243 }
244 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __func__, addr,
245 rval);
246 return rval;
247 } else if (addr > M.mem_size) {
248 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
249 __func__, addr);
250
251 HALT_SYS();
252 } else {
253
254 rval = in16le((void *) (M.mem_base + addr));
255 DEBUG_CHECK_VMEM_READ(addr, rval);
256 return rval;
257 }
258 return -1;
259}
260
261
262u32
263my_rdl(u32 addr)
264{
265 unsigned long translated_addr = addr;
266 u8 translated = biosemu_dev_translate_address(&translated_addr);
267 u32 rval;
268 if (translated != 0) {
269
270 DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
271 __func__, addr);
272
273
274
275 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
276
277
278
279 rval = ((u8) my_rdb(addr)) |
280 (((u8) my_rdb(addr + 1)) << 8) |
281 (((u8) my_rdb(addr + 2)) << 16) |
282 (((u8) my_rdb(addr + 3)) << 24);
283 } else {
284 if ((translated_addr & (u64) 0x3) == 0) {
285
286 set_ci();
287 rval = in32le((void *) translated_addr);
288 clr_ci();
289 } else {
290
291 set_ci();
292 rval = (*((u8 *) translated_addr)) |
293 (*((u8 *) translated_addr + 1) << 8) |
294 (*((u8 *) translated_addr + 2) << 16) |
295 (*((u8 *) translated_addr + 3) << 24);
296 clr_ci();
297 }
298 }
299 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __func__, addr,
300 rval);
301
302 return rval;
303 } else if (addr > M.mem_size) {
304 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
305 __func__, addr);
306
307 HALT_SYS();
308 } else {
309
310 rval = in32le((void *) (M.mem_base + addr));
311 switch (addr) {
312 case 0x46c:
313
314 update_time(rval);
315 rval = in32le((void *) (M.mem_base + addr));
316 break;
317 }
318 DEBUG_CHECK_VMEM_READ(addr, rval);
319 return rval;
320 }
321 return -1;
322}
323
324
325void
326my_wrb(u32 addr, u8 val)
327{
328 unsigned long translated_addr = addr;
329 u8 translated = biosemu_dev_translate_address(&translated_addr);
330 if (translated != 0) {
331
332 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
333 __func__, addr, val);
334
335 set_ci();
336 *((u8 *) translated_addr) = val;
337 clr_ci();
338 } else if (addr > M.mem_size) {
339 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
340 __func__, addr);
341
342 HALT_SYS();
343 } else {
344
345 DEBUG_CHECK_VMEM_WRITE(addr, val);
346 *((u8 *) (M.mem_base + addr)) = val;
347 }
348}
349
350void
351my_wrw(u32 addr, u16 val)
352{
353 unsigned long translated_addr = addr;
354 u8 translated = biosemu_dev_translate_address(&translated_addr);
355 if (translated != 0) {
356
357 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
358 __func__, addr, val);
359
360
361
362 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
363
364
365
366 my_wrb(addr, (u8) (val & 0x00FF));
367 my_wrb(addr + 1, (u8) ((val & 0xFF00) >> 8));
368 } else {
369 if ((translated_addr & (u64) 0x1) == 0) {
370
371 set_ci();
372 out16le((void *) translated_addr, val);
373 clr_ci();
374 } else {
375
376 set_ci();
377 *((u8 *) translated_addr) =
378 (u8) (val & 0x00FF);
379 *((u8 *) translated_addr + 1) =
380 (u8) ((val & 0xFF00) >> 8);
381 clr_ci();
382 }
383 }
384 } else if (addr > M.mem_size) {
385 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
386 __func__, addr);
387
388 HALT_SYS();
389 } else {
390
391 DEBUG_CHECK_VMEM_WRITE(addr, val);
392 out16le((void *) (M.mem_base + addr), val);
393 }
394}
395void
396my_wrl(u32 addr, u32 val)
397{
398 unsigned long translated_addr = addr;
399 u8 translated = biosemu_dev_translate_address(&translated_addr);
400 if (translated != 0) {
401
402 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
403 __func__, addr, val);
404
405
406
407 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
408
409
410
411 my_wrb(addr, (u8) (val & 0x000000FF));
412 my_wrb(addr + 1, (u8) ((val & 0x0000FF00) >> 8));
413 my_wrb(addr + 2, (u8) ((val & 0x00FF0000) >> 16));
414 my_wrb(addr + 3, (u8) ((val & 0xFF000000) >> 24));
415 } else {
416 if ((translated_addr & (u64) 0x3) == 0) {
417
418 set_ci();
419 out32le((void *) translated_addr, val);
420 clr_ci();
421 } else {
422
423 set_ci();
424 *((u8 *) translated_addr) =
425 (u8) (val & 0x000000FF);
426 *((u8 *) translated_addr + 1) =
427 (u8) ((val & 0x0000FF00) >> 8);
428 *((u8 *) translated_addr + 2) =
429 (u8) ((val & 0x00FF0000) >> 16);
430 *((u8 *) translated_addr + 3) =
431 (u8) ((val & 0xFF000000) >> 24);
432 clr_ci();
433 }
434 }
435 } else if (addr > M.mem_size) {
436 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
437 __func__, addr);
438
439 HALT_SYS();
440 } else {
441
442 DEBUG_CHECK_VMEM_WRITE(addr, val);
443 out32le((void *) (M.mem_base + addr), val);
444 }
445}
446
447
448
449
450
451void
452update_time(u32 cur_val)
453{
454
455
456 u64 ticks_per_day = tb_freq * 60 * 24;
457
458 u32 period_ticks = (55 * tb_freq) / 1000;
459 u64 curr_time = get_time();
460 u64 ticks_since_midnight = curr_time % ticks_per_day;
461 u32 periods_since_midnight = ticks_since_midnight / period_ticks;
462
463
464 if (periods_since_midnight < cur_val) {
465 my_wrb(0x470, 1);
466 }
467
468 my_wrl(0x46c, periods_since_midnight);
469}
470