* this routine is really greedy with selectors, and uses 5: * * 32-bit code selector: to return to kernel * 16-bit code selector: for running code * data selector: for 16-bit data * util selector: extra utility selector * args selector: to handle pointers * * the util selector is set from the util16 entry in bios16_args, if a * "U" specifier is seen. * * See <machin
| 318 | * See <machine/pc/bios.h> for description of format specifiers |
| 319 | */ |
| 320 | int |
| 321 | bios16(struct bios_args *args, char *fmt, ...) |
| 322 | { |
| 323 | char *p, *stack, *stack_top; |
| 324 | va_list ap; |
| 325 | int flags = BIOSCODE_FLAG | BIOSDATA_FLAG; |
| 326 | u_int i, arg_start, arg_end; |
| 327 | void *bios16_pmap_handle; |
| 328 | arg_start = 0xffffffff; |
| 329 | arg_end = 0; |
| 330 | |
| 331 | /* |
| 332 | * Some BIOS entrypoints attempt to copy the largest-case |
| 333 | * argument frame (in order to generalise handling for |
| 334 | * different entry types). If our argument frame is |
| 335 | * smaller than this, the BIOS will reach off the top of |
| 336 | * our constructed stack segment. Pad the top of the stack |
| 337 | * with some garbage to avoid this. |
| 338 | */ |
| 339 | stack = (caddr_t)PAGE_SIZE - 32; |
| 340 | |
| 341 | va_start(ap, fmt); |
| 342 | for (p = fmt; p && *p; p++) { |
| 343 | switch (*p) { |
| 344 | case 'p': /* 32-bit pointer */ |
| 345 | i = va_arg(ap, u_int); |
| 346 | arg_start = min(arg_start, i); |
| 347 | arg_end = max(arg_end, i); |
| 348 | flags |= BIOSARGS_FLAG; |
| 349 | stack -= 4; |
| 350 | break; |
| 351 | |
| 352 | case 'i': /* 32-bit integer */ |
| 353 | i = va_arg(ap, u_int); |
| 354 | stack -= 4; |
| 355 | break; |
| 356 | |
| 357 | case 'U': /* 16-bit selector */ |
| 358 | flags |= BIOSUTIL_FLAG; |
| 359 | /* FALLTHROUGH */ |
| 360 | case 'D': /* 16-bit selector */ |
| 361 | case 'C': /* 16-bit selector */ |
| 362 | stack -= 2; |
| 363 | break; |
| 364 | |
| 365 | case 's': /* 16-bit integer passed as an int */ |
| 366 | i = va_arg(ap, int); |
| 367 | stack -= 2; |
| 368 | break; |
| 369 | |
| 370 | default: |
| 371 | va_end(ap); |
| 372 | return (EINVAL); |
| 373 | } |
| 374 | } |
| 375 | va_end(ap); |
| 376 | |
| 377 | if (flags & BIOSARGS_FLAG) { |
no test coverage detected