bios.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Mostly done after the Scitech Bios emulation
  3. * Written by Hans-Jörg Frieden
  4. * Hyperion Entertainment
  5. */
  6. #include "x86emu.h"
  7. #include "glue.h"
  8. #undef DEBUG
  9. #ifdef DEBUG
  10. #define PRINTF(fmt, args...) printf(fmt, ## args)
  11. #else
  12. #define PRINTF(fmt, args...)
  13. #endif
  14. #define BIOS_SEG 0xFFF0
  15. #define PCIBIOS_SUCCESSFUL 0
  16. #define PCIBIOS_DEVICE_NOT_FOUND 0x86
  17. typedef unsigned char UBYTE;
  18. typedef unsigned short UWORD;
  19. typedef unsigned long ULONG;
  20. typedef char BYTE;
  21. typedef short WORT;
  22. typedef long LONG;
  23. static inline UBYTE read_byte(volatile UBYTE* from)
  24. {
  25. int x;
  26. asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
  27. return (UBYTE)x;
  28. }
  29. static inline void write_byte(volatile UBYTE *to, int x)
  30. {
  31. asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
  32. }
  33. static inline UWORD read_word_little(volatile UWORD *from)
  34. {
  35. int x;
  36. asm volatile ("lhbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m" (*from));
  37. return (UWORD)x;
  38. }
  39. static inline UWORD read_word_big(volatile UWORD *from)
  40. {
  41. int x;
  42. asm volatile ("lhz %0,%1\n eieio" : "=r" (x) : "m" (*from));
  43. return (UWORD)x;
  44. }
  45. static inline void write_word_little(volatile UWORD *to, int x)
  46. {
  47. asm volatile ("sthbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
  48. }
  49. static inline void write_word_big(volatile UWORD *to, int x)
  50. {
  51. asm volatile ("sth %1,%0\n eieio" : "=m" (*to) : "r" (x));
  52. }
  53. static inline ULONG read_long_little(volatile ULONG *from)
  54. {
  55. unsigned long x;
  56. asm volatile ("lwbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m"(*from));
  57. return (ULONG)x;
  58. }
  59. static inline ULONG read_long_big(volatile ULONG *from)
  60. {
  61. unsigned long x;
  62. asm volatile ("lwz %0,%1\n eieio" : "=r" (x) : "m" (*from));
  63. return (ULONG)x;
  64. }
  65. static inline void write_long_little(volatile ULONG *to, ULONG x)
  66. {
  67. asm volatile ("stwbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
  68. }
  69. static inline void write_long_big(volatile ULONG *to, ULONG x)
  70. {
  71. asm volatile ("stw %1,%0\n eieio" : "=m" (*to) : "r" (x));
  72. }
  73. #define port_to_mem(from) (0xFE000000|(from))
  74. #define in_byte(from) read_byte( (UBYTE *)port_to_mem(from))
  75. #define in_word(from) read_word_little((UWORD *)port_to_mem(from))
  76. #define in_long(from) read_long_little((ULONG *)port_to_mem(from))
  77. #define out_byte(to, val) write_byte((UBYTE *)port_to_mem(to), val)
  78. #define out_word(to, val) write_word_little((UWORD *)port_to_mem(to), val)
  79. #define out_long(to, val) write_long_little((ULONG *)port_to_mem(to), val)
  80. static void X86API undefined_intr(int intno)
  81. {
  82. extern u16 A1_rdw(u32 addr);
  83. if (A1_rdw(intno * 4 + 2) == BIOS_SEG)
  84. {
  85. PRINTF("Undefined interrupt %xh called AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
  86. intno, M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
  87. X86EMU_halt_sys();
  88. }
  89. else
  90. {
  91. PRINTF("Calling interrupt %xh, AL=%xh, AH=%xh\n", intno, M.x86.R_AL, M.x86.R_AH);
  92. X86EMU_prepareForInt(intno);
  93. }
  94. }
  95. static void X86API int42(int intno);
  96. static void X86API int15(int intno);
  97. static void X86API int10(int intno)
  98. {
  99. if (A1_rdw(intno*4+2) == BIOS_SEG)
  100. int42(intno);
  101. else
  102. {
  103. PRINTF("int10: branching to %04X:%04X, AL=%xh, AH=%xh\n", A1_rdw(intno*4+2), A1_rdw(intno*4),
  104. M.x86.R_AL, M.x86.R_AH);
  105. X86EMU_prepareForInt(intno);
  106. }
  107. }
  108. static void X86API int1A(int intno)
  109. {
  110. int device;
  111. switch(M.x86.R_AX)
  112. {
  113. case 0xB101: /* PCI Bios Present? */
  114. M.x86.R_AL = 0x00;
  115. M.x86.R_EDX = 0x20494350;
  116. M.x86.R_BX = 0x0210;
  117. M.x86.R_CL = 3;
  118. CLEAR_FLAG(F_CF);
  119. break;
  120. case 0xB102: /* Find device */
  121. device = mypci_find_device(M.x86.R_DX, M.x86.R_CX, M.x86.R_SI);
  122. if (device != -1)
  123. {
  124. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  125. M.x86.R_BH = mypci_bus(device);
  126. M.x86.R_BL = mypci_devfn(device);
  127. }
  128. else
  129. {
  130. M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
  131. }
  132. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  133. break;
  134. case 0xB103: /* Find PCI class code */
  135. M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
  136. /*printf("Find by class not yet implmented"); */
  137. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  138. break;
  139. case 0xB108: /* read config byte */
  140. M.x86.R_CL = mypci_read_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
  141. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  142. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  143. /*printf("read_config_byte %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  144. /* M.x86.R_CL); */
  145. break;
  146. case 0xB109: /* read config word */
  147. M.x86.R_CX = mypci_read_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
  148. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  149. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  150. /*printf("read_config_word %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  151. /* M.x86.R_CX); */
  152. break;
  153. case 0xB10A: /* read config dword */
  154. M.x86.R_ECX = mypci_read_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
  155. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  156. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  157. /*printf("read_config_long %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  158. /* M.x86.R_ECX); */
  159. break;
  160. case 0xB10B: /* write config byte */
  161. mypci_write_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
  162. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  163. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  164. /*printf("write_config_byte %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  165. /* M.x86.R_CL); */
  166. break;
  167. case 0xB10C: /* write config word */
  168. mypci_write_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
  169. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  170. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  171. /*printf("write_config_word %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  172. /* M.x86.R_CX); */
  173. break;
  174. case 0xB10D: /* write config dword */
  175. mypci_write_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
  176. M.x86.R_AH = PCIBIOS_SUCCESSFUL;
  177. CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
  178. /*printf("write_config_long %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
  179. /* M.x86.R_ECX); */
  180. break;
  181. default:
  182. PRINTF("BIOS int %xh: Unknown function AX=%04xh\n", intno, M.x86.R_AX);
  183. }
  184. }
  185. void bios_init(void)
  186. {
  187. int i;
  188. X86EMU_intrFuncs bios_intr_tab[256];
  189. for (i=0; i<256; i++)
  190. {
  191. write_long_little(M.mem_base+i*4, BIOS_SEG<<16);
  192. bios_intr_tab[i] = undefined_intr;
  193. }
  194. bios_intr_tab[0x10] = int10;
  195. bios_intr_tab[0x1A] = int1A;
  196. bios_intr_tab[0x42] = int42;
  197. bios_intr_tab[0x15] = int15;
  198. bios_intr_tab[0x6D] = int42;
  199. X86EMU_setupIntrFuncs(bios_intr_tab);
  200. video_init();
  201. }
  202. unsigned char setup_40x25[] =
  203. {
  204. 0x38, 0x28, 0x2d, 0x0a, 0x1f, 6, 0x19,
  205. 0x1c, 2, 7, 6, 7, 0, 0, 0, 0
  206. };
  207. unsigned char setup_80x25[] =
  208. {
  209. 0x71, 0x50, 0x5a, 0x0a, 0x1f, 6, 0x19,
  210. 0x1c, 2, 7, 6, 7, 0, 0, 0, 0
  211. };
  212. unsigned char setup_graphics[] =
  213. {
  214. 0x38, 0x28, 0x20, 0x0a, 0x7f, 6, 0x64,
  215. 0x70, 2, 1, 6, 7, 0, 0, 0, 0
  216. };
  217. unsigned char setup_bw[] =
  218. {
  219. 0x61, 0x50, 0x52, 0x0f, 0x19, 6, 0x19,
  220. 0x19, 2, 0x0d, 0x0b, 0x0c, 0, 0, 0, 0
  221. };
  222. unsigned char * setup_modes[] =
  223. {
  224. setup_40x25, /* mode 0: 40x25 bw text */
  225. setup_40x25, /* mode 1: 40x25 col text */
  226. setup_80x25, /* mode 2: 80x25 bw text */
  227. setup_80x25, /* mode 3: 80x25 col text */
  228. setup_graphics, /* mode 4: 320x200 col graphics */
  229. setup_graphics, /* mode 5: 320x200 bw graphics */
  230. setup_graphics, /* mode 6: 640x200 bw graphics */
  231. setup_bw /* mode 7: 80x25 mono text */
  232. };
  233. unsigned int setup_cols[] =
  234. {
  235. 40, 40, 80, 80, 40, 40, 80, 80
  236. };
  237. unsigned char setup_modesets[] =
  238. {
  239. 0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
  240. };
  241. unsigned int setup_bufsize[] =
  242. {
  243. 2048, 2048, 4096, 2096, 16384, 16384, 16384, 4096
  244. };
  245. void bios_set_mode(int mode)
  246. {
  247. int i;
  248. unsigned char mode_set = setup_modesets[mode]; /* Control register value */
  249. unsigned char *setup_regs = setup_modes[mode]; /* Register 3D4 Array */
  250. /* Switch video off */
  251. out_byte(0x3D8, mode_set & 0x37);
  252. /* Set up parameters at 3D4h */
  253. for (i=0; i<16; i++)
  254. {
  255. out_byte(0x3D4, (unsigned char)i);
  256. out_byte(0x3D5, *setup_regs);
  257. setup_regs++;
  258. }
  259. /* Enable video */
  260. out_byte(0x3D8, mode_set);
  261. /* Set overscan */
  262. if (mode == 6) out_byte(0x3D9, 0x3F);
  263. else out_byte(0x3D9, 0x30);
  264. }
  265. static void bios_print_string(void)
  266. {
  267. extern void video_bios_print_string(char *string, int x, int y, int attr, int count);
  268. char *s = (char *)(M.x86.R_ES<<4) + M.x86.R_BP;
  269. int attr;
  270. if (M.x86.R_AL & 0x02) attr = - 1;
  271. else attr = M.x86.R_BL;
  272. video_bios_print_string(s, M.x86.R_DH, M.x86.R_DL, attr, M.x86.R_CX);
  273. }
  274. static void X86API int42(int intno)
  275. {
  276. switch (M.x86.R_AH)
  277. {
  278. case 0x00:
  279. bios_set_mode(M.x86.R_AL);
  280. break;
  281. case 0x13:
  282. bios_print_string();
  283. break;
  284. default:
  285. PRINTF("Warning: VIDEO BIOS interrupt %xh unimplemented function %xh, AL = %xh\n",
  286. intno, M.x86.R_AH, M.x86.R_AL);
  287. }
  288. }
  289. static void X86API int15(int intno)
  290. {
  291. PRINTF("Called interrupt 15h: AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
  292. M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
  293. }