6 * This isn't nice, but there are a lot of incompatibilities in the U-Boot and scitech include
7 * files that this is the only really workable solution.
8 * Might be cleaned out later.
19 #define LOGIO(port, format, args...) if (dolog(port)) _printf(format , ## args)
21 #define LOGIO(port, format, args...)
25 #define LOGMEM(format, args...) _printf(format , ## args)
27 #define LOGMEM(format, args...)
31 #define PRINTF(format, args...) _printf(format , ## args)
33 #define PRINTF(format, argc...)
36 typedef unsigned char UBYTE;
37 typedef unsigned short UWORD;
38 typedef unsigned long ULONG;
44 #define EMULATOR_MEM_SIZE (1024*1024)
45 #define EMULATOR_BIOS_OFFSET 0xC0000
46 #define EMULATOR_STRAP_OFFSET 0x30000
47 #define EMULATOR_STACK_OFFSET 0x20000
48 #define EMULATOR_LOGO_OFFSET 0x40000 // If you change this, change the strap code, too
49 #define VIDEO_BASE (void *)0xFD0B8000
51 extern char *getenv(char *);
52 extern int tstc(void);
53 extern int getc(void);
54 extern unsigned char video_get_attr(void);
56 int atoi(char *string)
59 while (*string>='0' && *string <='9')
69 void cons_gets(char *buffer)
75 if (getenv("x86_runthru")) return; //FIXME:
76 while (c != 0x0D && c != 0x0A)
100 char *bios_date = "08/14/02";
102 UBYTE submodel = 0x00;
104 static inline UBYTE read_byte(volatile UBYTE* from)
107 asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
111 static inline void write_byte(volatile UBYTE *to, int x)
113 asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
116 static inline UWORD read_word_little(volatile UWORD *from)
119 asm volatile ("lhbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m" (*from));
123 static inline UWORD read_word_big(volatile UWORD *from)
126 asm volatile ("lhz %0,%1\n eieio" : "=r" (x) : "m" (*from));
130 static inline void write_word_little(volatile UWORD *to, int x)
132 asm volatile ("sthbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
135 static inline void write_word_big(volatile UWORD *to, int x)
137 asm volatile ("sth %1,%0\n eieio" : "=m" (*to) : "r" (x));
140 static inline ULONG read_long_little(volatile ULONG *from)
143 asm volatile ("lwbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m"(*from));
147 static inline ULONG read_long_big(volatile ULONG *from)
150 asm volatile ("lwz %0,%1\n eieio" : "=r" (x) : "m" (*from));
154 static inline void write_long_little(volatile ULONG *to, ULONG x)
156 asm volatile ("stwbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
159 static inline void write_long_big(volatile ULONG *to, ULONG x)
161 asm volatile ("stw %1,%0\n eieio" : "=m" (*to) : "r" (x));
164 static int log_init = 0;
165 static int log_do = 0;
166 static int log_low = 0;
170 if (log_init && log_do)
172 if (log_low && port > 0x400) return 0;
179 log_do = (getenv("x86_logio") != (char *)0);
180 log_low = (getenv("x86_loglow") != (char *)0);
183 if (log_low && port > 0x400) return 0;
190 // Converts an emulator address to a physical address.
191 // Handles all special cases (bios date, model etc), and might need work
192 u32 memaddr(u32 addr)
194 // if (addr >= 0xF0000 && addr < 0xFFFFF) printf("WARNING: Segment F access (0x%x)\n", addr);
195 // printf("MemAddr=%p\n", addr);
196 if (addr >= 0xA0000 && addr < 0xC0000)
197 return 0xFD000000 + addr;
198 else if (addr >= 0xFFFF5 && addr < 0xFFFFE)
200 return (u32)bios_date+addr-0xFFFF5;
202 else if (addr == 0xFFFFE)
204 else if (addr == 0xFFFFF)
205 return (u32)&submodel;
206 else if (addr >= 0x80000000)
208 //printf("Warning: High memory access at 0x%x\n", addr);
212 return (u32)M.mem_base+addr;
217 u8 a = read_byte((UBYTE *)memaddr(addr));
218 LOGMEM("rdb: %x -> %x\n", addr, a);
224 u16 a = read_word_little((UWORD *)memaddr(addr));
225 LOGMEM("rdw: %x -> %x\n", addr, a);
231 u32 a = read_long_little((ULONG *)memaddr(addr));
232 LOGMEM("rdl: %x -> %x\n", addr, a);
236 void A1_wrb(u32 addr, u8 val)
238 LOGMEM("wrb: %x <- %x\n", addr, val);
239 write_byte((UBYTE *)memaddr(addr), val);
242 void A1_wrw(u32 addr, u16 val)
244 LOGMEM("wrw: %x <- %x\n", addr, val);
245 write_word_little((UWORD *)memaddr(addr), val);
248 void A1_wrl(u32 addr, u32 val)
250 LOGMEM("wrl: %x <- %x\n", addr, val);
251 write_long_little((ULONG *)memaddr(addr), val);
254 X86EMU_memFuncs _A1_mem =
264 #define ARTICIAS_PCI_CFGADDR 0xfec00cf8
265 #define ARTICIAS_PCI_CFGDATA 0xfee00cfc
266 #define IOBASE 0xFE000000
268 #define in_byte(from) read_byte( (UBYTE *)port_to_mem(from))
269 #define in_word(from) read_word_little((UWORD *)port_to_mem(from))
270 #define in_long(from) read_long_little((ULONG *)port_to_mem(from))
271 #define out_byte(to, val) write_byte((UBYTE *)port_to_mem(to), val)
272 #define out_word(to, val) write_word_little((UWORD *)port_to_mem(to), val)
273 #define out_long(to, val) write_long_little((ULONG *)port_to_mem(to), val)
275 u32 port_to_mem(int port)
277 if (port >= 0xCFC && port <= 0xCFF) return 0xFEE00000+port;
278 else if (port >= 0xCF8 && port <= 0xCFB) return 0xFEC00000+port;
279 else return IOBASE + port;
285 //if (port == 0x3BA) return 0;
287 LOGIO(port, "inb: %Xh -> %d (%Xh)\n", port, a, a);
293 u16 a = in_word(port);
294 LOGIO(port, "inw: %Xh -> %d (%Xh)\n", port, a, a);
300 u32 a = in_long(port);
301 LOGIO(port, "inl: %Xh -> %d (%Xh)\n", port, a, a);
305 void A1_outb(int port, u8 val)
307 LOGIO(port, "outb: %Xh <- %d (%Xh)\n", port, val, val);
308 /* if (port == 0xCF8) port = 0xCFB;
309 else if (port == 0xCF9) port = 0xCFA;
310 else if (port == 0xCFA) port = 0xCF9;
311 else if (port == 0xCFB) port = 0xCF8;*/
315 void A1_outw(int port, u16 val)
317 LOGIO(port, "outw: %Xh <- %d (%Xh)\n", port, val, val);
321 void A1_outl(int port, u32 val)
323 LOGIO(port, "outl: %Xh <- %d (%Xh)\n", port, val, val);
327 X86EMU_pioFuncs _A1_pio =
337 static int reloced_ops = 0;
339 void reloc_ops(void *reloc_addr)
341 extern void (*x86emu_optab[256])(u8);
342 extern void (*x86emu_optab2[256])(u8);
343 extern void tables_relocate(unsigned int offset);
346 if (reloced_ops == 1) return;
349 delta = TEXT_BASE - (unsigned long)reloc_addr;
351 for (i=0; i<256; i++)
353 x86emu_optab[i] -= delta;
354 x86emu_optab2[i] -= delta;
357 _A1_mem.rdb = A1_rdb;
358 _A1_mem.rdw = A1_rdw;
359 _A1_mem.rdl = A1_rdl;
360 _A1_mem.wrb = A1_wrb;
361 _A1_mem.wrw = A1_wrw;
362 _A1_mem.wrl = A1_wrl;
364 _A1_pio.inb = A1_inb;
365 _A1_pio.inw = A1_inw;
366 _A1_pio.inl = A1_inl;
367 _A1_pio.outb = A1_outb;
368 _A1_pio.outw = A1_outw;
369 _A1_pio.outl = A1_outl;
371 tables_relocate(delta);
376 #define ANY_KEY(text) \
381 unsigned char more_strap[] = {
382 0xb4, 0x0, 0xb0, 0x2, 0xcd, 0x10,
384 #define MORE_STRAP_BYTES 6 // Additional bytes of strap code
387 unsigned char *done_msg="VGA Initialized\0";
389 int execute_bios(pci_dev_t gr_dev, void *reloc_addr)
391 extern void bios_init(void);
392 extern void remove_init_data(void);
393 extern int video_rows(void);
394 extern int video_cols(void);
395 extern int video_size(int, int);
405 int easteregg_active = 0;
410 unsigned char current_attr;
413 PRINTF("Removed init data from cache, now in RAM\n");
415 reloc_ops(reloc_addr);
416 PRINTF("Attempting to run emulator on %02x:%02x:%02x\n",
417 PCI_BUS(gr_dev), PCI_DEV(gr_dev), PCI_FUNC(gr_dev));
419 // Enable compatibility hole for emulator access to frame buffer
420 PRINTF("Enabling compatibility hole\n");
421 enable_compatibility_hole();
424 // FIXME: We shouldn't use this much memory really.
425 memset(&M, 0, sizeof(X86EMU_sysEnv));
426 M.mem_base = malloc(EMULATOR_MEM_SIZE);
427 M.mem_size = EMULATOR_MEM_SIZE;
431 PRINTF("Unable to allocate one megabyte for emulator\n");
435 if (attempt_map_rom(gr_dev, M.mem_base + EMULATOR_BIOS_OFFSET) == 0)
437 PRINTF("Error mapping rom. Emulation terminated\n");
442 s = getenv("x86_ask_start");
445 printf("Press 'q' to skip initialization, 'd' for dry init\n'i' for i/o session");
448 if (c == 'q') return 0;
451 extern void bios_set_mode(int mode);
455 if (c == 'i') do_inout();
466 easteregg_active = 1;
470 if (getenv("easteregg"))
472 easteregg_active = 1;
475 if (easteregg_active)
478 setenv("x86_mode", "1");
479 setenv("vga_fg_color", "11");
480 setenv("vga_bg_color", "1");
481 easteregg_active = 1;
485 strap = (u8*)M.mem_base + EMULATOR_STRAP_OFFSET;
488 char *m = getenv("x86_mode");
491 more_strap[3] = atoi(m);
492 if (more_strap[3] == 1) video_size(40, 25);
493 else video_size(80, 25);
498 * Poke the strap routine. This might need a bit of extending
499 * if there is a mode switch involved, i.e. we want to int10
500 * afterwards to set a different graphics mode, or alternatively
501 * there might be a different start address requirement if the
502 * ROM doesn't have an x86 image in its first image.
505 PRINTF("Poking strap...\n");
507 // FAR CALL c000:0003
508 *strap++ = 0x9A; *strap++ = 0x03; *strap++ = 0x00;
509 *strap++ = 0x00; *strap++ = 0xC0;
512 // insert additional strap code
513 for (i=0; i < MORE_STRAP_BYTES; i++)
515 *strap++ = more_strap[i];
521 PRINTF("Setting up logo data\n");
522 logo = (unsigned char *)M.mem_base + EMULATOR_LOGO_OFFSET;
529 * Setup the init parameters.
530 * Per PCI specs, AH must contain the bus and AL
531 * must contain the devfn, encoded as (dev<<3)|fn
534 // Execution starts here
535 M.x86.R_CS = SEG(EMULATOR_STRAP_OFFSET);
536 M.x86.R_IP = OFF(EMULATOR_STRAP_OFFSET);
538 // Stack at top of ram
539 M.x86.R_SS = SEG(EMULATOR_STACK_OFFSET);
540 M.x86.R_SP = OFF(EMULATOR_STACK_OFFSET);
543 M.x86.R_AH = PCI_BUS(gr_dev);
544 M.x86.R_AL = (PCI_DEV(gr_dev)<<3) | PCI_FUNC(gr_dev);
546 // Set the I/O and memory access functions
547 X86EMU_setupMemFuncs(&_A1_mem);
548 X86EMU_setupPioFuncs(&_A1_pio);
551 cfg = in_byte(0x61); // Get Misc control
552 cfg |= 0x01; // Enable timer 2
553 out_byte(0x61, cfg); // output again
556 out_byte(0x43, 0x54);
557 out_byte(0x41, 0x18);
559 out_byte(0x43, 0x36);
560 out_byte(0x40, 0x00);
561 out_byte(0x40, 0x00);
563 out_byte(0x43, 0xb6);
564 out_byte(0x42, 0x31);
565 out_byte(0x42, 0x13);
573 (void)in_byte(0x3BA);
574 (void)in_byte(0x3DA);
576 out_byte(0x61, 0xFC);
579 s = _getenv("x86_singlestep");
580 if (s && strcmp(s, "on")==0)
582 PRINTF("Enabling single stepping for debug\n");
588 PRINTF("Running emulator\n");
590 PRINTF("Done running emulator\n");
592 /* FIXME: Remove me */
593 pal_reset = getenv("x86_palette_reset");
594 if (pal_reset && strcmp(pal_reset, "on") == 0)
596 PRINTF("Palette reset\n");
597 //(void)in_byte(0x3da);
598 //out_byte(0x3c0, 0);
604 for (i=0; i<254; i++)
611 out_byte(0x3c0, 0x20);
613 /* FIXME: remove me */
615 if (easteregg_active)
617 extern void video_easteregg(void);
622 current_attr = video_get_attr();
623 fb = (u8 *)VIDEO_BASE;
624 for (i=0; i<video_rows()*video_cols()*2; i+=2)
627 *(fb+i+1) = current_attr;
630 fb = (u8 *)VIDEO_BASE + (video_rows())-1*(video_cols()*2);
631 for (i=0; i<video_cols(); i++)
634 *(fb + 2*i + 1) = 0x17;
646 if (getenv("x86_do_inout")) do_inout();
653 // Clean up the x86 mess
654 void shutdown_bios(void)
656 // disable_compatibility_hole();
657 // Free the memory associated
662 int to_int(char *buffer)
680 res += *buffer - '0';
720 void one_arg(char *buffer, int *a)
722 while (*buffer && *buffer != '\n')
724 if (*buffer == ' ') buffer++;
731 void two_args(char *buffer, int *a, int *b)
733 while (*buffer && *buffer != '\n')
735 if (*buffer == ' ') buffer++;
741 while (*buffer && *buffer != '\n')
743 if (*buffer != ' ') buffer++;
747 while (*buffer && *buffer != '\n')
749 if (*buffer == ' ') buffer++;
762 printf("In/Out Session\nUse 'i[bwl]' for in, 'o[bwl]' for out and 'q' to quit\n");
770 while (*arg1 != ' ' ) arg1++;
771 while (*arg1 == ' ') arg1++;
773 if (buffer[0] == 'i')
775 one_arg(buffer+2, &a);
779 printf("in_byte(%xh) = %xh\n", a, A1_inb(a));
782 printf("in_word(%xh) = %xh\n", a, A1_inw(a));
785 printf("in_dword(%xh) = %xh\n", a, A1_inl(a));
788 printf("Invalid length '%c'\n", buffer[1]);
792 else if (buffer[0] == 'o')
794 two_args(buffer+2, &a, &b);
798 printf("out_byte(%d, %d)\n", a, b);
802 printf("out_word(%d, %d)\n", a, b);
806 printf("out_long(%d, %d)\n", a, b);
810 printf("Invalid length '%c'\n", buffer[1]);
813 } else if (buffer[0] == 'q') return;