1 /* 2 * bioscalls.c - the lowlevel layer of the PnPBIOS driver 3 * 4 */ 5 6 #include <linux/types.h> 7 #include <linux/module.h> 8 #include <linux/init.h> 9 #include <linux/linkage.h> 10 #include <linux/kernel.h> 11 #include <linux/pnpbios.h> 12 #include <linux/device.h> 13 #include <linux/pnp.h> 14 #include <linux/mm.h> 15 #include <linux/smp.h> 16 #include <linux/slab.h> 17 #include <linux/kmod.h> 18 #include <linux/completion.h> 19 #include <linux/spinlock.h> 20 21 #include <asm/page.h> 22 #include <asm/desc.h> 23 #include <asm/system.h> 24 #include <asm/byteorder.h> 25 26 #include "pnpbios.h" 27 28 static struct { 29 u16 offset; 30 u16 segment; 31 } pnp_bios_callpoint; 32 33 34 /* The PnP BIOS entries in the GDT */ 35 #define PNP_GDT (GDT_ENTRY_PNPBIOS_BASE * 8) 36 37 #define PNP_CS32 (PNP_GDT+0x00) /* segment for calling fn */ 38 #define PNP_CS16 (PNP_GDT+0x08) /* code segment for BIOS */ 39 #define PNP_DS (PNP_GDT+0x10) /* data segment for BIOS */ 40 #define PNP_TS1 (PNP_GDT+0x18) /* transfer data segment */ 41 #define PNP_TS2 (PNP_GDT+0x20) /* another data segment */ 42 43 /* 44 * These are some opcodes for a "static asmlinkage" 45 * As this code is *not* executed inside the linux kernel segment, but in a 46 * alias at offset 0, we need a far return that can not be compiled by 47 * default (please, prove me wrong! this is *really* ugly!) 48 * This is the only way to get the bios to return into the kernel code, 49 * because the bios code runs in 16 bit protected mode and therefore can only 50 * return to the caller if the call is within the first 64kB, and the linux 51 * kernel begins at offset 3GB... 52 */ 53 54 asmlinkage void pnp_bios_callfunc(void); 55 56 __asm__( 57 ".text \n" 58 __ALIGN_STR "\n" 59 "pnp_bios_callfunc:\n" 60 " pushl %edx \n" 61 " pushl %ecx \n" 62 " pushl %ebx \n" 63 " pushl %eax \n" 64 " lcallw *pnp_bios_callpoint\n" 65 " addl $16, %esp \n" 66 " lret \n" 67 ".previous \n" 68 ); 69 70 #define Q_SET_SEL(cpu, selname, address, size) \ 71 do { \ 72 set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \ 73 set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ 74 } while(0) 75 76 #define Q2_SET_SEL(cpu, selname, address, size) \ 77 do { \ 78 set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \ 79 set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ 80 } while(0) 81 82 static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; 83 84 /* 85 * At some point we want to use this stack frame pointer to unwind 86 * after PnP BIOS oopses. 87 */ 88 89 u32 pnp_bios_fault_esp; 90 u32 pnp_bios_fault_eip; 91 u32 pnp_bios_is_utter_crap = 0; 92 93 static spinlock_t pnp_bios_lock; 94 95 96 /* 97 * Support Functions 98 */ 99 100 static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, 101 u16 arg4, u16 arg5, u16 arg6, u16 arg7, 102 void *ts1_base, u32 ts1_size, 103 void *ts2_base, u32 ts2_size) 104 { 105 unsigned long flags; 106 u16 status; 107 struct desc_struct save_desc_40; 108 int cpu; 109 110 /* 111 * PnP BIOSes are generally not terribly re-entrant. 112 * Also, don't rely on them to save everything correctly. 113 */ 114 if(pnp_bios_is_utter_crap) 115 return PNP_FUNCTION_NOT_SUPPORTED; 116 117 cpu = get_cpu(); 118 save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8]; 119 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc; 120 121 /* On some boxes IRQ's during PnP BIOS calls are deadly. */ 122 spin_lock_irqsave(&pnp_bios_lock, flags); 123 124 /* The lock prevents us bouncing CPU here */ 125 if (ts1_size) 126 Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size); 127 if (ts2_size) 128 Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size); 129 130 __asm__ __volatile__( 131 "pushl %%ebp\n\t" 132 "pushl %%edi\n\t" 133 "pushl %%esi\n\t" 134 "pushl %%ds\n\t" 135 "pushl %%es\n\t" 136 "pushl %%fs\n\t" 137 "pushl %%gs\n\t" 138 "pushfl\n\t" 139 "movl %%esp, pnp_bios_fault_esp\n\t" 140 "movl $1f, pnp_bios_fault_eip\n\t" 141 "lcall %5,%6\n\t" 142 "1:popfl\n\t" 143 "popl %%gs\n\t" 144 "popl %%fs\n\t" 145 "popl %%es\n\t" 146 "popl %%ds\n\t" 147 "popl %%esi\n\t" 148 "popl %%edi\n\t" 149 "popl %%ebp\n\t" 150 : "=a" (status) 151 : "0" ((func) | (((u32)arg1) << 16)), 152 "b" ((arg2) | (((u32)arg3) << 16)), 153 "c" ((arg4) | (((u32)arg5) << 16)), 154 "d" ((arg6) | (((u32)arg7) << 16)), 155 "i" (PNP_CS32), 156 "i" (0) 157 : "memory" 158 ); 159 spin_unlock_irqrestore(&pnp_bios_lock, flags); 160 161 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40; 162 put_cpu(); 163 164 /* If we get here and this is set then the PnP BIOS faulted on us. */ 165 if(pnp_bios_is_utter_crap) 166 { 167 printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n"); 168 printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n"); 169 printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n"); 170 } 171 172 return status; 173 } 174 175 void pnpbios_print_status(const char * module, u16 status) 176 { 177 switch(status) { 178 case PNP_SUCCESS: 179 printk(KERN_ERR "PnPBIOS: %s: function successful\n", module); 180 break; 181 case PNP_NOT_SET_STATICALLY: 182 printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module); 183 break; 184 case PNP_UNKNOWN_FUNCTION: 185 printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module); 186 break; 187 case PNP_FUNCTION_NOT_SUPPORTED: 188 printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module); 189 break; 190 case PNP_INVALID_HANDLE: 191 printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module); 192 break; 193 case PNP_BAD_PARAMETER: 194 printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module); 195 break; 196 case PNP_SET_FAILED: 197 printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module); 198 break; 199 case PNP_EVENTS_NOT_PENDING: 200 printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module); 201 break; 202 case PNP_SYSTEM_NOT_DOCKED: 203 printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module); 204 break; 205 case PNP_NO_ISA_PNP_CARDS: 206 printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module); 207 break; 208 case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES: 209 printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module); 210 break; 211 case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY: 212 printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module); 213 break; 214 case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT: 215 printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module); 216 break; 217 case PNP_BUFFER_TOO_SMALL: 218 printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module); 219 break; 220 case PNP_USE_ESCD_SUPPORT: 221 printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module); 222 break; 223 case PNP_MESSAGE_NOT_SUPPORTED: 224 printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module); 225 break; 226 case PNP_HARDWARE_ERROR: 227 printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module); 228 break; 229 default: 230 printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status); 231 break; 232 } 233 } 234 235 236 /* 237 * PnP BIOS Low Level Calls 238 */ 239 240 #define PNP_GET_NUM_SYS_DEV_NODES 0x00 241 #define PNP_GET_SYS_DEV_NODE 0x01 242 #define PNP_SET_SYS_DEV_NODE 0x02 243 #define PNP_GET_EVENT 0x03 244 #define PNP_SEND_MESSAGE 0x04 245 #define PNP_GET_DOCKING_STATION_INFORMATION 0x05 246 #define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09 247 #define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a 248 #define PNP_GET_APM_ID_TABLE 0x0b 249 #define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40 250 #define PNP_GET_ESCD_INFO 0x41 251 #define PNP_READ_ESCD 0x42 252 #define PNP_WRITE_ESCD 0x43 253 254 /* 255 * Call PnP BIOS with function 0x00, "get number of system device nodes" 256 */ 257 static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data) 258 { 259 u16 status; 260 if (!pnp_bios_present()) 261 return PNP_FUNCTION_NOT_SUPPORTED; 262 status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0, 263 data, sizeof(struct pnp_dev_node_info), NULL, 0); 264 data->no_nodes &= 0xff; 265 return status; 266 } 267 268 int pnp_bios_dev_node_info(struct pnp_dev_node_info *data) 269 { 270 int status = __pnp_bios_dev_node_info( data ); 271 if ( status ) 272 pnpbios_print_status( "dev_node_info", status ); 273 return status; 274 } 275 276 /* 277 * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible 278 * death if they are asked to access the "current" configuration. 279 * Therefore, if it's a matter of indifference, it's better to call 280 * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0. 281 */ 282 283 /* 284 * Call PnP BIOS with function 0x01, "get system device node" 285 * Input: *nodenum = desired node, 286 * boot = whether to get nonvolatile boot (!=0) 287 * or volatile current (0) config 288 * Output: *nodenum=next node or 0xff if no more nodes 289 */ 290 static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) 291 { 292 u16 status; 293 if (!pnp_bios_present()) 294 return PNP_FUNCTION_NOT_SUPPORTED; 295 if ( !boot && pnpbios_dont_use_current_config ) 296 return PNP_FUNCTION_NOT_SUPPORTED; 297 status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0, 298 nodenum, sizeof(char), data, 65536); 299 return status; 300 } 301 302 int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) 303 { 304 int status; 305 status = __pnp_bios_get_dev_node( nodenum, boot, data ); 306 if ( status ) 307 pnpbios_print_status( "get_dev_node", status ); 308 return status; 309 } 310 311 312 /* 313 * Call PnP BIOS with function 0x02, "set system device node" 314 * Input: *nodenum = desired node, 315 * boot = whether to set nonvolatile boot (!=0) 316 * or volatile current (0) config 317 */ 318 static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) 319 { 320 u16 status; 321 if (!pnp_bios_present()) 322 return PNP_FUNCTION_NOT_SUPPORTED; 323 if ( !boot && pnpbios_dont_use_current_config ) 324 return PNP_FUNCTION_NOT_SUPPORTED; 325 status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0, 326 data, 65536, NULL, 0); 327 return status; 328 } 329 330 int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) 331 { 332 int status; 333 status = __pnp_bios_set_dev_node( nodenum, boot, data ); 334 if ( status ) { 335 pnpbios_print_status( "set_dev_node", status ); 336 return status; 337 } 338 if ( !boot ) { /* Update devlist */ 339 status = pnp_bios_get_dev_node( &nodenum, boot, data ); 340 if ( status ) 341 return status; 342 } 343 return status; 344 } 345 346 #if needed 347 /* 348 * Call PnP BIOS with function 0x03, "get event" 349 */ 350 static int pnp_bios_get_event(u16 *event) 351 { 352 u16 status; 353 if (!pnp_bios_present()) 354 return PNP_FUNCTION_NOT_SUPPORTED; 355 status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0, 356 event, sizeof(u16), NULL, 0); 357 return status; 358 } 359 #endif 360 361 #if needed 362 /* 363 * Call PnP BIOS with function 0x04, "send message" 364 */ 365 static int pnp_bios_send_message(u16 message) 366 { 367 u16 status; 368 if (!pnp_bios_present()) 369 return PNP_FUNCTION_NOT_SUPPORTED; 370 status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0); 371 return status; 372 } 373 #endif 374 375 /* 376 * Call PnP BIOS with function 0x05, "get docking station information" 377 */ 378 int pnp_bios_dock_station_info(struct pnp_docking_station_info *data) 379 { 380 u16 status; 381 if (!pnp_bios_present()) 382 return PNP_FUNCTION_NOT_SUPPORTED; 383 status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, 384 data, sizeof(struct pnp_docking_station_info), NULL, 0); 385 return status; 386 } 387 388 #if needed 389 /* 390 * Call PnP BIOS with function 0x09, "set statically allocated resource 391 * information" 392 */ 393 static int pnp_bios_set_stat_res(char *info) 394 { 395 u16 status; 396 if (!pnp_bios_present()) 397 return PNP_FUNCTION_NOT_SUPPORTED; 398 status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, 399 info, *((u16 *) info), 0, 0); 400 return status; 401 } 402 #endif 403 404 /* 405 * Call PnP BIOS with function 0x0a, "get statically allocated resource 406 * information" 407 */ 408 static int __pnp_bios_get_stat_res(char *info) 409 { 410 u16 status; 411 if (!pnp_bios_present()) 412 return PNP_FUNCTION_NOT_SUPPORTED; 413 status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, 414 info, 65536, NULL, 0); 415 return status; 416 } 417 418 int pnp_bios_get_stat_res(char *info) 419 { 420 int status; 421 status = __pnp_bios_get_stat_res( info ); 422 if ( status ) 423 pnpbios_print_status( "get_stat_res", status ); 424 return status; 425 } 426 427 #if needed 428 /* 429 * Call PnP BIOS with function 0x0b, "get APM id table" 430 */ 431 static int pnp_bios_apm_id_table(char *table, u16 *size) 432 { 433 u16 status; 434 if (!pnp_bios_present()) 435 return PNP_FUNCTION_NOT_SUPPORTED; 436 status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0, 437 table, *size, size, sizeof(u16)); 438 return status; 439 } 440 #endif 441 442 /* 443 * Call PnP BIOS with function 0x40, "get isa pnp configuration structure" 444 */ 445 static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) 446 { 447 u16 status; 448 if (!pnp_bios_present()) 449 return PNP_FUNCTION_NOT_SUPPORTED; 450 status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, 451 data, sizeof(struct pnp_isa_config_struc), NULL, 0); 452 return status; 453 } 454 455 int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) 456 { 457 int status; 458 status = __pnp_bios_isapnp_config( data ); 459 if ( status ) 460 pnpbios_print_status( "isapnp_config", status ); 461 return status; 462 } 463 464 /* 465 * Call PnP BIOS with function 0x41, "get ESCD info" 466 */ 467 static int __pnp_bios_escd_info(struct escd_info_struc *data) 468 { 469 u16 status; 470 if (!pnp_bios_present()) 471 return ESCD_FUNCTION_NOT_SUPPORTED; 472 status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS, 473 data, sizeof(struct escd_info_struc), NULL, 0); 474 return status; 475 } 476 477 int pnp_bios_escd_info(struct escd_info_struc *data) 478 { 479 int status; 480 status = __pnp_bios_escd_info( data ); 481 if ( status ) 482 pnpbios_print_status( "escd_info", status ); 483 return status; 484 } 485 486 /* 487 * Call PnP BIOS function 0x42, "read ESCD" 488 * nvram_base is determined by calling escd_info 489 */ 490 static int __pnp_bios_read_escd(char *data, u32 nvram_base) 491 { 492 u16 status; 493 if (!pnp_bios_present()) 494 return ESCD_FUNCTION_NOT_SUPPORTED; 495 status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, 496 data, 65536, __va(nvram_base), 65536); 497 return status; 498 } 499 500 int pnp_bios_read_escd(char *data, u32 nvram_base) 501 { 502 int status; 503 status = __pnp_bios_read_escd( data, nvram_base ); 504 if ( status ) 505 pnpbios_print_status( "read_escd", status ); 506 return status; 507 } 508 509 #if needed 510 /* 511 * Call PnP BIOS function 0x43, "write ESCD" 512 */ 513 static int pnp_bios_write_escd(char *data, u32 nvram_base) 514 { 515 u16 status; 516 if (!pnp_bios_present()) 517 return ESCD_FUNCTION_NOT_SUPPORTED; 518 status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, 519 data, 65536, __va(nvram_base), 65536); 520 return status; 521 } 522 #endif 523 524 525 /* 526 * Initialization 527 */ 528 529 void pnpbios_calls_init(union pnp_bios_install_struct *header) 530 { 531 int i; 532 spin_lock_init(&pnp_bios_lock); 533 pnp_bios_callpoint.offset = header->fields.pm16offset; 534 pnp_bios_callpoint.segment = PNP_CS16; 535 536 set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); 537 _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); 538 for(i=0; i < NR_CPUS; i++) 539 { 540 Q2_SET_SEL(i, PNP_CS32, &pnp_bios_callfunc, 64 * 1024); 541 Q_SET_SEL(i, PNP_CS16, header->fields.pm16cseg, 64 * 1024); 542 Q_SET_SEL(i, PNP_DS, header->fields.pm16dseg, 64 * 1024); 543 } 544 } 545