1/* 2 * XFree86 int10 module 3 * execute BIOS int 10h calls in x86 real mode environment 4 * Copyright 1999 Egbert Eich 5 */ 6#ifdef HAVE_XORG_CONFIG_H 7#include <xorg-config.h> 8#endif 9 10#include <string.h> 11#include <stdlib.h> 12 13#include "xf86.h" 14#include "xf86_OSproc.h" 15#include "compiler.h" 16#include "xf86Pci.h" 17#define _INT10_PRIVATE 18#if 0 19#include "int10Defines.h" 20#endif 21#include "xf86int10.h" 22 23#define REG pInt 24 25typedef enum { 26 OPT_NOINT10, 27 OPT_INIT_PRIMARY, 28} INT10Opts; 29 30static const OptionInfoRec INT10Options[] = { 31 {OPT_NOINT10, "NoINT10", OPTV_BOOLEAN, {0}, FALSE }, 32 {OPT_INIT_PRIMARY, "InitPrimary", OPTV_BOOLEAN, {0}, FALSE }, 33 { -1, NULL, OPTV_NONE, {0}, FALSE }, 34}; 35 36#ifdef DEBUG 37void 38dprint(unsigned long start, unsigned long size) 39{ 40 int i,j; 41 char *c = (char *)start; 42 43 for (j = 0; j < (size >> 4); j++) { 44 char *d = c; 45 ErrorF("\n0x%lx: ",(unsigned long)c); 46 for (i = 0; i<16; i++) 47 ErrorF("%2.2x ",(unsigned char) (*(c++))); 48 c = d; 49 for (i = 0; i<16; i++) { 50 ErrorF("%c",((((CARD8)(*c)) > 32) && (((CARD8)(*c)) < 128)) ? 51 (unsigned char) (*(c)): '.'); 52 c++; 53 } 54 } 55 ErrorF("\n"); 56} 57#endif 58 59#ifndef _PC 60/* 61 * here we are really paranoid about faking a "real" 62 * BIOS. Most of this information was pulled from 63 * dosemu. 64 */ 65void 66setup_int_vect(xf86Int10InfoPtr pInt) 67{ 68 int i; 69 70 /* let the int vects point to the SYS_BIOS seg */ 71 for (i = 0; i < 0x80; i++) { 72 MEM_WW(pInt, i << 2, 0); 73 MEM_WW(pInt, (i << 2) + 2, SYS_BIOS >> 4); 74 } 75 76 reset_int_vect(pInt); 77 /* font tables default location (int 1F) */ 78 MEM_WW(pInt,0x1f<<2,0xfa6e); 79 80 /* int 11 default location (Get Equipment Configuration) */ 81 MEM_WW(pInt, 0x11 << 2, 0xf84d); 82 /* int 12 default location (Get Conventional Memory Size) */ 83 MEM_WW(pInt, 0x12 << 2, 0xf841); 84 /* int 15 default location (I/O System Extensions) */ 85 MEM_WW(pInt, 0x15 << 2, 0xf859); 86 /* int 1A default location (RTC, PCI and others) */ 87 MEM_WW(pInt, 0x1a << 2, 0xff6e); 88 /* int 05 default location (Bound Exceeded) */ 89 MEM_WW(pInt, 0x05 << 2, 0xff54); 90 /* int 08 default location (Double Fault) */ 91 MEM_WW(pInt, 0x08 << 2, 0xfea5); 92 /* int 13 default location (Disk) */ 93 MEM_WW(pInt, 0x13 << 2, 0xec59); 94 /* int 0E default location (Page Fault) */ 95 MEM_WW(pInt, 0x0e << 2, 0xef57); 96 /* int 17 default location (Parallel Port) */ 97 MEM_WW(pInt, 0x17 << 2, 0xefd2); 98 /* fdd table default location (int 1e) */ 99 MEM_WW(pInt, 0x1e << 2, 0xefc7); 100 101 /* Set Equipment flag to VGA */ 102 i = MEM_RB(pInt, 0x0410) & 0xCF; 103 MEM_WB(pInt, 0x0410, i); 104 /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */ 105} 106#endif 107 108int 109setup_system_bios(void *base_addr) 110{ 111 char *base = (char *) base_addr; 112 113 /* 114 * we trap the "industry standard entry points" to the BIOS 115 * and all other locations by filling them with "hlt" 116 * TODO: implement hlt-handler for these 117 */ 118 memset(base, 0xf4, 0x10000); 119 120 /* set bios date */ 121 strcpy(base + 0x0FFF5, "06/11/99"); 122 /* set up eisa ident string */ 123 strcpy(base + 0x0FFD9, "PCI_ISA"); 124 /* write system model id for IBM-AT */ 125 *((unsigned char *)(base + 0x0FFFE)) = 0xfc; 126 127 return 1; 128} 129 130void 131reset_int_vect(xf86Int10InfoPtr pInt) 132{ 133 /* 134 * This table is normally located at 0xF000:0xF0A4. However, int 0x42, 135 * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom 136 * 64kB. Note that because this data doesn't survive POST, int 0x42 should 137 * only be used during EGA/VGA BIOS initialisation. 138 */ 139 static const CARD8 VideoParms[] = { 140 /* Timing for modes 0x00 & 0x01 */ 141 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c, 142 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 143 /* Timing for modes 0x02 & 0x03 */ 144 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c, 145 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 146 /* Timing for modes 0x04, 0x05 & 0x06 */ 147 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70, 148 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 149 /* Timing for mode 0x07 */ 150 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, 151 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, 152 /* Display page lengths in little endian order */ 153 0x00, 0x08, /* Modes 0x00 and 0x01 */ 154 0x00, 0x10, /* Modes 0x02 and 0x03 */ 155 0x00, 0x40, /* Modes 0x04 and 0x05 */ 156 0x00, 0x40, /* Modes 0x06 and 0x07 */ 157 /* Number of columns for each mode */ 158 40, 40, 80, 80, 40, 40, 80, 80, 159 /* CGA Mode register value for each mode */ 160 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29, 161 /* Padding */ 162 0x00, 0x00, 0x00, 0x00 163 }; 164 int i; 165 166 for (i = 0; i < sizeof(VideoParms); i++) 167 MEM_WB(pInt, i + (0x1000 - sizeof(VideoParms)), VideoParms[i]); 168 MEM_WW(pInt, 0x1d << 2, 0x1000 - sizeof(VideoParms)); 169 MEM_WW(pInt, (0x1d << 2) + 2, 0); 170 171 MEM_WW(pInt, 0x10 << 2, 0xf065); 172 MEM_WW(pInt, (0x10 << 2) + 2, SYS_BIOS >> 4); 173 MEM_WW(pInt, 0x42 << 2, 0xf065); 174 MEM_WW(pInt, (0x42 << 2) + 2, SYS_BIOS >> 4); 175 MEM_WW(pInt, 0x6D << 2, 0xf065); 176 MEM_WW(pInt, (0x6D << 2) + 2, SYS_BIOS >> 4); 177} 178 179void 180set_return_trap(xf86Int10InfoPtr pInt) 181{ 182 /* 183 * Here we set the exit condition: We return when we encounter 184 * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory. 185 */ 186 MEM_WB(pInt, 0x0600, 0xf4); 187 188 /* 189 * Allocate a segment for the stack 190 */ 191 xf86Int10AllocPages(pInt, 1, &pInt->stackseg); 192} 193 194void * 195xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex) 196{ 197 EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex); 198 OptionInfoPtr options = NULL; 199 200 if (pEnt->device) { 201 pointer configOptions = NULL; 202 203 /* Check if xf86CollectOptions() has already been called */ 204 if (((pEnt->index < 0) || 205 !pScrn || 206 !(configOptions = pScrn->options)) && 207 pEnt->device) 208 configOptions = pEnt->device->options; 209 210 if (configOptions) { 211 if (!(options = (OptionInfoPtr) malloc(sizeof(INT10Options)))) 212 return NULL; 213 214 (void)memcpy(options, INT10Options, sizeof(INT10Options)); 215 xf86ProcessOptions(pScrn->scrnIndex, configOptions, options); 216 } 217 } 218 free(pEnt); 219 220 return options; 221} 222 223Bool 224int10skip(const void* options) 225{ 226 Bool noint10 = FALSE; 227 228 if (!options) return FALSE; 229 230 xf86GetOptValBool(options, OPT_NOINT10, &noint10); 231 return noint10; 232} 233 234Bool 235int10_check_bios(int scrnIndex, int codeSeg, const unsigned char* vbiosMem) 236{ 237 int size; 238 239 if ((codeSeg & 0x1f) || /* Not 512-byte aligned otherwise */ 240 ((codeSeg << 4) < V_BIOS) || 241 ((codeSeg << 4) >= SYS_SIZE)) 242 return FALSE; 243 244 if (xf86IsPc98()) 245 return FALSE; 246 247 if ((*vbiosMem != 0x55) || (*(vbiosMem+1) != 0xAA) || !*(vbiosMem+2)) 248 return FALSE; 249 250 size = *(vbiosMem + 2) * 512; 251 252 if ((size + (codeSeg << 4)) > SYS_SIZE) 253 return FALSE; 254 255 if (bios_checksum(vbiosMem, size)) 256 xf86DrvMsg(scrnIndex, X_INFO, "Bad V_BIOS checksum\n"); 257 258 return TRUE; 259} 260 261Bool 262initPrimary(const void* options) 263{ 264 Bool initPrimary = FALSE; 265 266 if (!options) return FALSE; 267 268 xf86GetOptValBool(options, OPT_INIT_PRIMARY, &initPrimary); 269 return initPrimary; 270} 271 272BusType 273xf86int10GetBiosLocationType(const xf86Int10InfoPtr pInt) 274{ 275 BusType location_type; 276 277 EntityInfoPtr pEnt = xf86GetEntityInfo(pInt->entityIndex); 278 location_type = pEnt->location.type; 279 free(pEnt); 280 281 return location_type; 282} 283 284 285#define CHECK_V_SEGMENT_RANGE(x) \ 286 if (((x) << 4) < V_BIOS) { \ 287 xf86DrvMsg(pInt->scrnIndex, X_ERROR, \ 288 "V_BIOS address 0x%lx out of range\n", \ 289 (unsigned long)(x) << 4); \ 290 return FALSE; \ 291 } 292 293Bool 294xf86int10GetBiosSegment(xf86Int10InfoPtr pInt, void *base) 295{ 296 unsigned i; 297 int cs = ~0; 298 int segments[4]; 299 300 segments[0] = MEM_RW(pInt, (0x10 << 2) + 2); 301 segments[1] = MEM_RW(pInt, (0x42 << 2) + 2); 302 segments[2] = V_BIOS >> 4; 303 segments[3] = ~0; 304 305 for (i = 0; segments[i] != ~0; i++) { 306 unsigned char * vbiosMem; 307 308 cs = segments[i]; 309 310 CHECK_V_SEGMENT_RANGE(cs); 311 vbiosMem = (unsigned char *)base + (cs << 4); 312 if (int10_check_bios(pInt->scrnIndex, cs, vbiosMem)) { 313 break; 314 } 315 } 316 317 if (segments[i] == ~0) { 318 xf86DrvMsg(pInt->scrnIndex, X_ERROR, "No V_BIOS found\n"); 319 return FALSE; 320 } 321 322 xf86DrvMsg(pInt->scrnIndex, X_INFO, "Primary V_BIOS segment is: 0x%lx\n", 323 (unsigned long)cs); 324 325 pInt->BIOSseg = cs; 326 return TRUE; 327} 328