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