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