1 /*
2  * Mostly done after the Scitech Bios emulation
3  * Written by Hans-J�rg Frieden
4  * Hyperion Entertainment
5  */
6 #include <common.h>
7 #include "scitech/include/x86emu/x86emu.h"
8 #include "glue.h"
9 #include "scitech/include/x86emu/regs.h"
10 #include "x86interface.h"
11 
12 #undef DEBUG
13 
14 #ifdef DEBUG
15 #define PRINTF(fmt, args...) printf(fmt, ## args)
16 #else
17 #define PRINTF(fmt, args...)
18 #endif
19 
20 #define BIOS_SEG 0xFFF0
21 #define PCIBIOS_SUCCESSFUL 0
22 #define PCIBIOS_DEVICE_NOT_FOUND 0x86
23 
24 typedef unsigned char UBYTE;
25 typedef unsigned short UWORD;
26 typedef unsigned long ULONG;
27 
28 typedef char BYTE;
29 typedef short WORT;
30 typedef long LONG;
31 
32 //#define port_to_mem(from) (CFG_ISA_IO_BASE_ADDRESS|(from))
33 /*
34 #define in_byte(from) in8( (UBYTE *)port_to_mem(from))
35 #define in_word(from) in16r((UWORD *)port_to_mem(from))
36 #define in_long(from) in32r(ULONG *)port_to_mem(from))
37 #define out_byte(to, val) out8((UBYTE *)port_to_mem(to), val)
38 #define out_word(to, val) out16r((UWORD *)port_to_mem(to), val)
39 #define out_long(to, val) out32r((ULONG *)port_to_mem(to), val)
40 */
41 
42 #define out_byte(to, val) out8((UBYTE *)port_to_mem(to), val)
43 
undefined_intr(int intno)44 static void X86API undefined_intr(int intno)
45 {
46     PRINTF("X86API undefined_intr\n");
47 
48     extern u16 A1_rdw(u32 addr);
49     if (A1_rdw(intno * 4 + 2) == BIOS_SEG)
50     {
51     	PRINTF("Undefined interrupt 0x%x called AX = 0x%x, BX = 0x%x, CX = 0x%x, DX = 0x%x\n",
52     	   intno, M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
53     	X86EMU_halt_sys();
54     }
55     else
56     {
57     	PRINTF("Calling interrupt %xh, AL=%xh, AH=%xh\n", intno, M.x86.R_AL, M.x86.R_AH);
58     	X86EMU_prepareForInt(intno);
59     }
60 }
61 
62 static void X86API int42(int intno);
63 static void X86API int15(int intno);
64 
int10(int intno)65 static void X86API int10(int intno)
66 {
67     PRINTF("X86API int10\n");
68 
69     if (A1_rdw(intno*4+2) == BIOS_SEG)
70     	int42(intno);
71     else
72     {
73     	PRINTF("int10: branching to %04X:%04X, AL=%xh, AH=%xh\n", A1_rdw(intno*4+2), A1_rdw(intno*4),
74 	       M.x86.R_AL, M.x86.R_AH);
75     	X86EMU_prepareForInt(intno);
76     }
77 }
78 
int1A(int intno)79 static void X86API int1A(int intno)
80 {
81     PRINTF("X86API int1A\n");
82 
83     int device;
84 
85     switch(M.x86.R_AX)
86     {
87     case 0xB101: // PCI Bios Present?
88        	M.x86.R_AL  = 0x00;
89     	M.x86.R_EDX = 0x20494350;
90     	M.x86.R_BX  = 0x0210;
91     	M.x86.R_CL  = 3;
92     	CLEAR_FLAG(F_CF);
93     	break;
94     case 0xB102: // Find device
95     	device = mypci_find_device(M.x86.R_DX, M.x86.R_CX, M.x86.R_SI);
96     	if (device != -1)
97     	{
98     	    M.x86.R_AH = PCIBIOS_SUCCESSFUL;
99     	    M.x86.R_BH = mypci_bus(device);
100     	    M.x86.R_BL = mypci_devfn(device);
101     	}
102     	else
103     	{
104     	    M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
105     	}
106     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
107     	break;
108     case 0xB103: // Find PCI class code
109     	M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
110     	printf("Find by class not yet implmented");
111     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
112     	break;
113     case 0xB108: // read config byte
114     	M.x86.R_CL = mypci_read_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
115     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
116     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
117     	PRINTF("read_config_byte %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
118     	break;
119     case 0xB109: // read config word
120     	M.x86.R_CX = mypci_read_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
121     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
122     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
123     	PRINTF("read_config_word %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
124     	break;
125     case 0xB10A: // read config dword
126     	M.x86.R_ECX = mypci_read_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
127     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
128     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
129     	PRINTF("read_config_long %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
130     	break;
131     case 0xB10B: // write config byte
132     	mypci_write_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
133     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
134     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
135     	PRINTF("write_config_byte %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
136     	break;
137     case 0xB10C: // write config word
138     	mypci_write_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
139     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
140     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
141     	PRINTF("write_config_word %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
142     	break;
143     case 0xB10D: // write config dword
144     	mypci_write_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
145     	M.x86.R_AH = PCIBIOS_SUCCESSFUL;
146     	CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
147     	PRINTF("write_config_long %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
148     	break;
149     default:
150     	PRINTF("BIOS int %xh: Unknown function AX=%04xh\n", intno, M.x86.R_AX);
151     }
152 }
153 
bios_init(void)154 void bios_init(void)
155 {
156     int i;
157     X86EMU_intrFuncs bios_intr_tab[256];
158 
159     PRINTF("Interrupt table\n");
160     for (i=0; i<256; i++)
161     {
162 	    out32r((volatile ULONG *)(M.mem_base+i*4), BIOS_SEG<<16);
163 	    bios_intr_tab[i] = undefined_intr;
164     }
165 
166     bios_intr_tab[0x10] = int10;
167     bios_intr_tab[0x1A] = int1A;
168     bios_intr_tab[0x42] = int42;
169     bios_intr_tab[0x15] = int15;
170 
171     bios_intr_tab[0x6D] = int42;
172 
173     X86EMU_setupIntrFuncs(bios_intr_tab);
174     // why here? Because it is needed.
175     //PRINTF("video_init\n");
176     //video_init();
177 }
178 
179 unsigned char setup_40x25[] =
180 {
181     0x38, 0x28, 0x2d, 0x0a, 0x1f, 6, 0x19,
182     0x1c, 2, 7, 6, 7, 0, 0, 0, 0
183 };
184 
185 unsigned char setup_80x25[] =
186 {
187     0x71, 0x50, 0x5a, 0x0a, 0x1f, 6, 0x19,
188     0x1c, 2, 7, 6, 7, 0, 0, 0, 0
189 };
190 
191 unsigned char setup_graphics[] =
192 {
193     0x38, 0x28, 0x20, 0x0a, 0x7f, 6, 0x64,
194     0x70, 2, 1, 6, 7, 0, 0, 0, 0
195 };
196 
197 unsigned char setup_bw[] =
198 {
199     0x61, 0x50, 0x52, 0x0f, 0x19, 6, 0x19,
200     0x19, 2, 0x0d, 0x0b, 0x0c, 0, 0, 0, 0
201 };
202 
203 unsigned char * setup_modes[] =
204 {
205     setup_40x25,     // mode 0: 40x25 bw text
206     setup_40x25,     // mode 1: 40x25 col text
207     setup_80x25,     // mode 2: 80x25 bw text
208     setup_80x25,     // mode 3: 80x25 col text
209     setup_graphics,  // mode 4: 320x200 col graphics
210     setup_graphics,  // mode 5: 320x200 bw graphics
211     setup_graphics,  // mode 6: 640x200 bw graphics
212     setup_bw         // mode 7: 80x25 mono text
213 };
214 
215 unsigned int setup_cols[] =
216 {
217     40, 40, 80, 80, 40, 40, 80, 80
218 };
219 
220 unsigned char setup_modesets[] =
221 {
222      0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
223 };
224 
225 unsigned int setup_bufsize[] =
226 {
227     2048, 2048, 4096, 2096, 16384, 16384, 16384, 4096
228 };
229 
230 int reloc_mode_done = 0;
231 
reloc_mode_table(void * reloc_addr)232 void reloc_mode_table(void *reloc_addr)
233 {
234     unsigned long delta;
235     int i;
236 
237     if (reloc_mode_done)
238 	return;
239 
240     reloc_mode_done = 1;
241 
242     PRINTF("reloc_addr = %p\n", reloc_addr);
243     delta = TEXT_BASE - (unsigned long)reloc_addr;
244     PRINTF("delta = %p\n", delta);
245 
246     for (i = 0; i < sizeof(setup_modes)/sizeof(unsigned char *); i++)
247 	    setup_modes[i] = (unsigned char *) ((unsigned long)setup_modes[i] - delta);
248 }
249 
bios_set_mode(int mode)250 void bios_set_mode(int mode)
251 {
252     int i;
253     unsigned char mode_set = setup_modesets[mode]; // Control register value
254     unsigned char *setup_regs = setup_modes[mode]; // Register 3D4 Array
255 
256     flush_cache(0, 32768);
257 
258     PRINTF("bios_set_mode: mode = %d, setup_regs = %p\n", mode, setup_regs);
259 
260     // Switch video off
261     out_byte(0x3D8, mode_set & 0x37);
262 
263     // Set up parameters at 3D4h
264     for (i=0; i<16; i++)
265     {
266     	out_byte(0x3D4, (unsigned char)i);
267 	    out_byte(0x3D5,  *setup_regs);
268     	setup_regs++;
269     }
270 
271     // Enable video
272     out_byte(0x3D8, mode_set);
273 
274     // Set overscan
275     if (mode == 6) out_byte(0x3D9, 0x3F);
276     else           out_byte(0x3D9, 0x30);
277 
278     PRINTF("bios_set_mode: done\n");
279 }
280 /*
281 static void bios_print_string(void)
282 {
283     extern void video_bios_print_string(char *string, int x, int y, int attr, int count);
284     //char *s = (char *)(M.x86.R_ES<<4) + M.x86.R_BP;
285     int attr;
286     if (M.x86.R_AL & 0x02) attr = - 1;
287     else                   attr = M.x86.R_BL;
288     //video_bios_print_string(s, M.x86.R_DH, M.x86.R_DL, attr, M.x86.R_CX);
289 }
290 */
int42(int intno)291 static void X86API int42(int intno)
292 {
293     PRINTF("int42: AH = 0x%x, AL = 0x%x, AX = 0x%x, BX = 0x%x\n",
294 		    M.x86.R_AH, M.x86.R_AL, M.x86.R_AX, M.x86.R_BX);
295 
296     switch (M.x86.R_AH)
297     {
298     case 0x00:
299 	bios_set_mode(M.x86.R_AL);
300 	break;
301     case 0x13:
302 	//bios_print_string();
303 	break;
304     default:
305 	PRINTF("Warning: VIDEO BIOS interrupt %xh unimplemented function %xh, AL = %xh\n",
306 	       intno, M.x86.R_AH, M.x86.R_AL);
307 	break;
308     }
309 }
310 
int15(int intno)311 static void X86API int15(int intno)
312 {
313     PRINTF("Called interrupt 15h: AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
314 	   M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
315 //#if 0
316     if (M.x86.R_AX == 0x04e08)
317     {
318 		switch (M.x86.R_BL)
319 		{
320 /*
321 		    case 0x06:			// Power Management Mode request
322 			M.x86.R_BL = 0;		// Assume APM
323 			M.x86.R_AL = 0;
324 			break;
325 
326 		    case 0x05:			// Get TV standard
327 				M.x86.R_BX = 0xff;	// Select No TV
328 				M.x86.R_AL = 0;
329 				break;
330 */
331 		    case 0x01:					 // Get Request Display
332 			    if ((M.x86.R_BH & 0x08) == 0x08)
333 			    {
334 					M.x86.R_BL = 0x08;	// DVI
335 					M.x86.R_BH = 0;
336 					M.x86.R_AL = 0;		// supported
337 					PRINTF("DVI Monitor Found\n");
338 				}
339 
340 			    if (((M.x86.R_BH & 0x08) == 0x08) || ((M.x86.R_BH & 0x02) == 0x02))
341 			    {
342 					M.x86.R_BL = 0x02;	// CRT
343 					M.x86.R_BH = 0;
344 					M.x86.R_AL = 0;		// supported
345 					PRINTF("CRT Monitor Found\n");
346 				}
347 
348 			    if (((M.x86.R_BH & 0x08) == 0x08) || ((M.x86.R_BH & 0x04) == 0x04))
349 			    {
350 					M.x86.R_BL = 0x04;	// CRT 2
351 					M.x86.R_BH = 0;
352 					M.x86.R_AX = 0;		// supported
353 					PRINTF("CRT2 Monitor Found\n");
354 				}
355 
356 				break;
357 
358 		    default:
359 				PRINTF("Subfunction %d not implemented\n", M.x86.R_BL);
360 				M.x86.R_AL = 2;		// Not supported
361 				break;
362 		}
363 		PRINTF("Result: AX = %xh, BX = %xh\n", M.x86.R_AX, M.x86.R_BX);
364     }
365 //#endif
366 //    // For now, just declare this interrupt as not implemented
367 //    M.x86.R_AX = 2;
368 }
369