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