boot1.c revision 329135
1/*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * Copyright (c) 2001 Robert Drehmel 5 * All rights reserved. 6 * Copyright (c) 2014 Nathan Whitehorn 7 * All rights reserved. 8 * Copyright (c) 2015 Eric McCorkle 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms are freely 12 * permitted provided that the above copyright notice and this 13 * paragraph and the following disclaimer are duplicated in all 14 * such forms. 15 * 16 * This software is provided "AS IS" and without any express or 17 * implied warranties, including, without limitation, the implied 18 * warranties of merchantability and fitness for a particular 19 * purpose. 20 */ 21 22#include <sys/cdefs.h> 23__FBSDID("$FreeBSD: stable/11/sys/boot/efi/boot1/boot1.c 329135 2018-02-11 20:04:34Z kevans $"); 24 25#include <sys/param.h> 26#include <sys/disk.h> 27#include <machine/elf.h> 28#include <machine/stdarg.h> 29#include <stand.h> 30#include <disk.h> 31 32#include <efi.h> 33#include <efilib.h> 34#include <efiprot.h> 35#include <eficonsctl.h> 36#ifdef EFI_ZFS_BOOT 37#include <libzfs.h> 38#endif 39typedef CHAR16 efi_char; 40#include <efichar.h> 41 42#include <bootstrap.h> 43 44#include "efi_drivers.h" 45#include "efizfs.h" 46#include "paths.h" 47 48static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); 49#ifdef EFI_DEBUG 50#define DPRINTF(fmt, args...) printf(fmt, ##args) 51#define DSTALL(d) BS->Stall(d) 52#else 53#define DPRINTF(fmt, ...) {} 54#define DSTALL(d) {} 55#endif 56 57struct arch_switch archsw; /* MI/MD interface boundary */ 58 59static const efi_driver_t *efi_drivers[] = { 60 NULL 61}; 62 63extern struct console efi_console; 64#if defined(__amd64__) || defined(__i386__) 65extern struct console comconsole; 66extern struct console nullconsole; 67#endif 68 69#ifdef EFI_ZFS_BOOT 70uint64_t pool_guid; 71#endif 72 73struct fs_ops *file_system[] = { 74#ifdef EFI_ZFS_BOOT 75 &zfs_fsops, 76#endif 77 &dosfs_fsops, 78#ifdef EFI_UFS_BOOT 79 &ufs_fsops, 80#endif 81 &cd9660_fsops, 82 &nfs_fsops, 83 &gzipfs_fsops, 84 &bzipfs_fsops, 85 NULL 86}; 87 88struct devsw *devsw[] = { 89 &efipart_hddev, 90 &efipart_fddev, 91 &efipart_cddev, 92#ifdef EFI_ZFS_BOOT 93 &zfs_dev, 94#endif 95 NULL 96}; 97 98struct console *consoles[] = { 99 &efi_console, 100 NULL 101}; 102 103static EFI_LOADED_IMAGE *boot_image; 104static EFI_DEVICE_PATH *imgpath; 105static EFI_DEVICE_PATH *imgprefix; 106 107/* Definitions we don't actually need for boot, but we need to define 108 * to make the linker happy. 109 */ 110struct file_format *file_formats[] = { NULL }; 111 112struct netif_driver *netif_drivers[] = { NULL }; 113 114static int 115efi_autoload(void) 116{ 117 printf("******** Boot block should not call autoload\n"); 118 return (-1); 119} 120 121static ssize_t 122efi_copyin(const void *src __unused, vm_offset_t dest __unused, 123 const size_t len __unused) 124{ 125 printf("******** Boot block should not call copyin\n"); 126 return (-1); 127} 128 129static ssize_t 130efi_copyout(vm_offset_t src __unused, void *dest __unused, 131 const size_t len __unused) 132{ 133 printf("******** Boot block should not call copyout\n"); 134 return (-1); 135} 136 137static ssize_t 138efi_readin(int fd __unused, vm_offset_t dest __unused, 139 const size_t len __unused) 140{ 141 printf("******** Boot block should not call readin\n"); 142 return (-1); 143} 144 145/* The initial number of handles used to query EFI for partitions. */ 146#define NUM_HANDLES_INIT 24 147 148static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 149static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 150static EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID; 151 152static EFI_STATUS 153do_load(const char *filepath, void **bufp, size_t *bufsize) 154{ 155 struct stat st; 156 void *buf = NULL; 157 int fd, err; 158 size_t fsize, remaining; 159 ssize_t readsize; 160 161 if ((fd = open(filepath, O_RDONLY)) < 0) { 162 return (ENOTSUP); 163 } 164 165 if ((err = fstat(fd, &st)) != 0) { 166 goto close_file; 167 } 168 169 fsize = st.st_size; 170 171 if ((buf = malloc(fsize)) == NULL) { 172 err = ENOMEM; 173 goto close_file; 174 } 175 176 remaining = fsize; 177 178 do { 179 if ((readsize = read(fd, buf, fsize)) < 0) { 180 err = (-readsize); 181 goto free_buf; 182 } 183 184 remaining -= readsize; 185 } while(remaining != 0); 186 187 close(fd); 188 *bufsize = st.st_size; 189 *bufp = buf; 190 191 close_file: 192 close(fd); 193 194 return errno_to_efi_status(err); 195 196 free_buf: 197 free(buf); 198 goto close_file; 199} 200 201static EFI_STATUS 202efi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr) 203{ 204 CHAR16 *var = NULL; 205 size_t len; 206 EFI_STATUS rv; 207 208 utf8_to_ucs2(varname, &var, &len); 209 if (var == NULL) 210 return (EFI_OUT_OF_RESOURCES); 211 rv = RS->SetVariable(var, &FreeBSDBootVarGUID, 212 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 213 (ucs2len(valstr) + 1) * sizeof(efi_char), valstr); 214 free(var); 215 return (rv); 216} 217 218static int 219probe_fs(const char *filepath) 220{ 221 int fd; 222 223 if ((fd = open(filepath, O_RDONLY)) < 0) { 224 return (ENOTSUP); 225 } 226 227 close(fd); 228 229 return (0); 230} 231 232static int 233probe_dev(struct devsw *dev, int unit, const char *filepath) 234{ 235 struct devdesc currdev; 236 char *devname; 237 int err; 238 239 currdev.d_dev = dev; 240 currdev.d_type = currdev.d_dev->dv_type; 241 currdev.d_unit = unit; 242 currdev.d_opendata = NULL; 243 devname = efi_fmtdev(&currdev); 244 245 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 246 env_nounset); 247 248 err = probe_fs(filepath); 249 250 return (err); 251} 252 253static bool 254check_preferred(EFI_HANDLE *h) 255{ 256 EFI_DEVICE_PATH *path = efi_lookup_devpath(h); 257 bool out; 258 259 if ((path = efi_lookup_devpath(h)) == NULL) 260 return (false); 261 262 out = efi_devpath_is_prefix(imgpath, path) || 263 efi_devpath_is_prefix(imgprefix, path); 264 265 return (out); 266} 267 268bool 269efi_zfs_is_preferred(EFI_HANDLE *h) 270{ 271 return (check_preferred(h)); 272} 273 274static int 275load_preferred(EFI_LOADED_IMAGE *img, const char *filepath, void **bufp, 276 size_t *bufsize, EFI_HANDLE *handlep) 277{ 278 pdinfo_list_t *pdi_list; 279 pdinfo_t *dp, *pp; 280 char *devname; 281 282#ifdef EFI_ZFS_BOOT 283 /* Did efi_zfs_probe() detect the boot pool? */ 284 if (pool_guid != 0) { 285 struct zfs_devdesc currdev; 286 287 currdev.d_dev = &zfs_dev; 288 currdev.d_unit = 0; 289 currdev.d_type = currdev.d_dev->dv_type; 290 currdev.d_opendata = NULL; 291 currdev.pool_guid = pool_guid; 292 currdev.root_guid = 0; 293 devname = efi_fmtdev(&currdev); 294 295 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 296 env_nounset); 297 298 if (probe_fs(filepath) == 0 && 299 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 300 *handlep = efizfs_get_handle_by_guid(pool_guid); 301 return (0); 302 } 303 } 304#endif /* EFI_ZFS_BOOT */ 305 306 /* We have device lists for hd, cd, fd, walk them all. */ 307 pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); 308 STAILQ_FOREACH(dp, pdi_list, pd_link) { 309 struct disk_devdesc currdev; 310 311 currdev.d_dev = &efipart_hddev; 312 currdev.d_type = currdev.d_dev->dv_type; 313 currdev.d_unit = dp->pd_unit; 314 currdev.d_opendata = NULL; 315 currdev.d_slice = -1; 316 currdev.d_partition = -1; 317 devname = efi_fmtdev(&currdev); 318 319 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 320 env_nounset); 321 322 if (check_preferred(dp->pd_handle) && 323 probe_fs(filepath) == 0 && 324 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 325 *handlep = dp->pd_handle; 326 return (0); 327 } 328 329 /* Assuming GPT partitioning. */ 330 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { 331 if (check_preferred(pp->pd_handle)) { 332 currdev.d_slice = pp->pd_unit; 333 currdev.d_partition = 255; 334 devname = efi_fmtdev(&currdev); 335 336 env_setenv("currdev", EV_VOLATILE, devname, 337 efi_setcurrdev, env_nounset); 338 339 if (probe_fs(filepath) == 0 && 340 do_load(filepath, bufp, bufsize) == 341 EFI_SUCCESS) { 342 *handlep = pp->pd_handle; 343 return (0); 344 } 345 } 346 } 347 } 348 349 pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); 350 STAILQ_FOREACH(dp, pdi_list, pd_link) { 351 if ((dp->pd_handle == img->DeviceHandle || 352 dp->pd_alias == img->DeviceHandle || 353 check_preferred(dp->pd_handle)) && 354 probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && 355 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 356 *handlep = dp->pd_handle; 357 return (0); 358 } 359 } 360 361 pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); 362 STAILQ_FOREACH(dp, pdi_list, pd_link) { 363 if ((dp->pd_handle == img->DeviceHandle || 364 check_preferred(dp->pd_handle)) && 365 probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && 366 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 367 *handlep = dp->pd_handle; 368 return (0); 369 } 370 } 371 372 return (ENOENT); 373} 374 375static int 376load_all(const char *filepath, void **bufp, size_t *bufsize, 377 EFI_HANDLE *handlep) 378{ 379 pdinfo_list_t *pdi_list; 380 pdinfo_t *dp, *pp; 381 zfsinfo_list_t *zfsi_list; 382 zfsinfo_t *zi; 383 char *devname; 384 385#ifdef EFI_ZFS_BOOT 386 zfsi_list = efizfs_get_zfsinfo_list(); 387 STAILQ_FOREACH(zi, zfsi_list, zi_link) { 388 struct zfs_devdesc currdev; 389 390 currdev.d_dev = &zfs_dev; 391 currdev.d_unit = 0; 392 currdev.d_type = currdev.d_dev->dv_type; 393 currdev.d_opendata = NULL; 394 currdev.pool_guid = zi->zi_pool_guid; 395 currdev.root_guid = 0; 396 devname = efi_fmtdev(&currdev); 397 398 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 399 env_nounset); 400 401 if (probe_fs(filepath) == 0 && 402 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 403 *handlep = zi->zi_handle; 404 405 return (0); 406 } 407 } 408#endif /* EFI_ZFS_BOOT */ 409 410 /* We have device lists for hd, cd, fd, walk them all. */ 411 pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); 412 STAILQ_FOREACH(dp, pdi_list, pd_link) { 413 struct disk_devdesc currdev; 414 415 currdev.d_dev = &efipart_hddev; 416 currdev.d_type = currdev.d_dev->dv_type; 417 currdev.d_unit = dp->pd_unit; 418 currdev.d_opendata = NULL; 419 currdev.d_slice = -1; 420 currdev.d_partition = -1; 421 devname = efi_fmtdev(&currdev); 422 423 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 424 env_nounset); 425 426 if (probe_fs(filepath) == 0 && 427 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 428 *handlep = dp->pd_handle; 429 430 return (0); 431 } 432 433 /* Assuming GPT partitioning. */ 434 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { 435 currdev.d_slice = pp->pd_unit; 436 currdev.d_partition = 255; 437 devname = efi_fmtdev(&currdev); 438 439 env_setenv("currdev", EV_VOLATILE, devname, 440 efi_setcurrdev, env_nounset); 441 442 if (probe_fs(filepath) == 0 && 443 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 444 *handlep = pp->pd_handle; 445 446 return (0); 447 } 448 } 449 } 450 451 pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); 452 STAILQ_FOREACH(dp, pdi_list, pd_link) { 453 if (probe_dev(&efipart_cddev, dp->pd_unit, filepath) == 0 && 454 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 455 *handlep = dp->pd_handle; 456 457 return (0); 458 } 459 } 460 461 pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); 462 STAILQ_FOREACH(dp, pdi_list, pd_link) { 463 if (probe_dev(&efipart_fddev, dp->pd_unit, filepath) == 0 && 464 do_load(filepath, bufp, bufsize) == EFI_SUCCESS) { 465 *handlep = dp->pd_handle; 466 467 return (0); 468 } 469 } 470 471 return (ENOENT); 472} 473 474static EFI_STATUS 475load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize) 476{ 477 /* Try the preferred handles first, then all the handles */ 478 if (load_preferred(boot_image, PATH_LOADER_EFI, bufp, bufsize, 479 handlep) == 0) { 480 return (0); 481 } 482 483 if (load_all(PATH_LOADER_EFI, bufp, bufsize, handlep) == 0) { 484 return (0); 485 } 486 487 return (EFI_NOT_FOUND); 488} 489 490/* 491 * try_boot only returns if it fails to load the loader. If it succeeds 492 * it simply boots, otherwise it returns the status of last EFI call. 493 */ 494static EFI_STATUS 495try_boot(void) 496{ 497 size_t bufsize, loadersize, cmdsize; 498 void *buf, *loaderbuf; 499 char *cmd; 500 EFI_HANDLE fshandle; 501 EFI_HANDLE loaderhandle; 502 EFI_LOADED_IMAGE *loaded_image; 503 EFI_STATUS status; 504 EFI_DEVICE_PATH *fspath; 505 506 status = load_loader(&fshandle, &loaderbuf, &loadersize); 507 508 if (status != EFI_SUCCESS) { 509 return (status); 510 } 511 512 fspath = NULL; 513 if (status == EFI_SUCCESS) { 514 status = BS->OpenProtocol(fshandle, &DevicePathGUID, 515 (void **)&fspath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 516 if (status != EFI_SUCCESS) { 517 DPRINTF("Failed to get image DevicePath (%lu)\n", 518 EFI_ERROR_CODE(status)); 519 } 520 DPRINTF("filesystem device path: %s\n", devpath_str(fspath)); 521 } 522 523 /* 524 * Read in and parse the command line from /boot.config or /boot/config, 525 * if present. We'll pass it the next stage via a simple ASCII 526 * string. loader.efi has a hack for ASCII strings, so we'll use that to 527 * keep the size down here. We only try to read the alternate file if 528 * we get EFI_NOT_FOUND because all other errors mean that the boot_module 529 * had troubles with the filesystem. We could return early, but we'll let 530 * loading the actual kernel sort all that out. Since these files are 531 * optional, we don't report errors in trying to read them. 532 */ 533 cmd = NULL; 534 cmdsize = 0; 535 status = do_load(PATH_DOTCONFIG, &buf, &bufsize); 536 if (status == EFI_NOT_FOUND) 537 status = do_load(PATH_CONFIG, &buf, &bufsize); 538 if (status == EFI_SUCCESS) { 539 cmdsize = bufsize + 1; 540 cmd = malloc(cmdsize); 541 if (cmd == NULL) 542 goto errout; 543 memcpy(cmd, buf, bufsize); 544 cmd[bufsize] = '\0'; 545 free(buf); 546 buf = NULL; 547 } 548 549 if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(fspath), 550 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 551 printf("Failed to load image, size: %zu, (%lu)\n", 552 loadersize, EFI_ERROR_CODE(status)); 553 goto errout; 554 } 555 556 if ((status = BS->OpenProtocol(loaderhandle, &LoadedImageGUID, 557 (VOID**)&loaded_image, IH, NULL, 558 EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { 559 printf("Failed to query LoadedImage (%lu)\n", 560 EFI_ERROR_CODE(status)); 561 goto errout; 562 } 563 564 if (cmd != NULL) 565 printf(" command args: %s\n", cmd); 566 567 loaded_image->DeviceHandle = fshandle; 568 loaded_image->LoadOptionsSize = cmdsize; 569 loaded_image->LoadOptions = cmd; 570 571 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 572 DSTALL(1000000); 573 DPRINTF("."); 574 DSTALL(1000000); 575 DPRINTF("."); 576 DSTALL(1000000); 577 DPRINTF("."); 578 DSTALL(1000000); 579 DPRINTF("."); 580 DSTALL(1000000); 581 DPRINTF(".\n"); 582 583 if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 584 EFI_SUCCESS) { 585 printf("Failed to start image (%lu)\n", 586 EFI_ERROR_CODE(status)); 587 loaded_image->LoadOptionsSize = 0; 588 loaded_image->LoadOptions = NULL; 589 } 590 591errout: 592 if (cmd != NULL) 593 free(cmd); 594 if (buf != NULL) 595 free(buf); 596 if (loaderbuf != NULL) 597 free(loaderbuf); 598 599 return (status); 600} 601 602EFI_STATUS 603main(int argc __unused, CHAR16 *argv[] __unused) 604{ 605 EFI_STATUS status; 606 607 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 608 UINTN i, max_dim, best_mode, cols, rows; 609 CHAR16 *text; 610 611 archsw.arch_autoload = efi_autoload; 612 archsw.arch_getdev = efi_getdev; 613 archsw.arch_copyin = efi_copyin; 614 archsw.arch_copyout = efi_copyout; 615 archsw.arch_readin = efi_readin; 616#ifdef EFI_ZFS_BOOT 617 /* Note this needs to be set before ZFS init. */ 618 archsw.arch_zfs_probe = efi_zfs_probe; 619#endif 620 621 /* Init the time source */ 622 efi_time_init(); 623 cons_probe(); 624 625 /* 626 * Reset the console and find the best text mode. 627 */ 628 conout = ST->ConOut; 629 conout->Reset(conout, TRUE); 630 max_dim = best_mode = 0; 631 632 for (i = 0; ; i++) { 633 status = conout->QueryMode(conout, i, &cols, &rows); 634 if (EFI_ERROR(status)) 635 break; 636 if (cols * rows > max_dim) { 637 max_dim = cols * rows; 638 best_mode = i; 639 } 640 } 641 642 if (max_dim > 0) 643 conout->SetMode(conout, best_mode); 644 645 conout->EnableCursor(conout, TRUE); 646 conout->ClearScreen(conout); 647 648 /* Print this here, so people know it's at least starting. */ 649 printf("\n>> FreeBSD EFI boot block\n"); 650 printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 651 652 /* Get the image path and trim it to get the disk on which we 653 * found this loader. 654 */ 655 if ((status = BS->OpenProtocol(IH, &LoadedImageGUID, 656 (VOID**)&boot_image, IH, NULL, 657 EFI_OPEN_PROTOCOL_GET_PROTOCOL)) != EFI_SUCCESS) { 658 panic("Failed to query LoadedImage (%lu)\n", 659 EFI_ERROR_CODE(status)); 660 } 661 662 /* Determine the devpath of our image so we can prefer it. */ 663 status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&boot_image); 664 imgpath = NULL; 665 if (status == EFI_SUCCESS) { 666 text = efi_devpath_name(boot_image->FilePath); 667 printf(" Load Path: %S\n", text); 668 efi_setenv_freebsd_wcs("Boot1Path", text); 669 efi_free_devpath_name(text); 670 671 status = BS->HandleProtocol(boot_image->DeviceHandle, &DevicePathGUID, 672 (void **)&imgpath); 673 if (status != EFI_SUCCESS) { 674 DPRINTF("Failed to get image DevicePath (%lu)\n", 675 EFI_ERROR_CODE(status)); 676 } else { 677 text = efi_devpath_name(imgpath); 678 printf(" Load Device: %S\n", text); 679 efi_setenv_freebsd_wcs("Boot1Dev", text); 680 efi_free_devpath_name(text); 681 } 682 683 } 684 685 /* The loaded image device path ends with a partition, then a 686 * file path. Trim them both to get the actual disk. 687 */ 688 if ((imgprefix = efi_devpath_trim(imgpath)) == NULL || 689 (imgprefix = efi_devpath_trim(imgprefix)) == NULL) { 690 panic("Couldn't trim device path"); 691 } 692 693 /* 694 * Initialize the block cache. Set the upper limit. 695 */ 696 bcache_init(32768, 512); 697 698 printf("\n Initializing modules:"); 699 700 for (i = 0; efi_drivers[i] != NULL; i++) { 701 printf(" %s", efi_drivers[i]->name); 702 if (efi_drivers[i]->init != NULL) 703 efi_drivers[i]->init(); 704 } 705 706 for (i = 0; devsw[i] != NULL; i++) { 707 if (devsw[i]->dv_init != NULL) { 708 printf(" %s", devsw[i]->dv_name); 709 (devsw[i]->dv_init)(); 710 } 711 } 712 713 putchar('\n'); 714 715 try_boot(); 716 717 /* If we get here, we're out of luck... */ 718 efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!"); 719} 720 721/* 722 * OK. We totally give up. Exit back to EFI with a sensible status so 723 * it can try the next option on the list. 724 */ 725static void 726efi_panic(EFI_STATUS s, const char *fmt, ...) 727{ 728 va_list ap; 729 730 printf("panic: "); 731 va_start(ap, fmt); 732 vprintf(fmt, ap); 733 va_end(ap); 734 printf("\n"); 735 736 BS->Exit(IH, s, 0, NULL); 737} 738