Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/efi/loader/main.c
34878 views
1
/*-
2
* Copyright (c) 2008-2010 Rui Paulo
3
* Copyright (c) 2006 Marcel Moolenaar
4
* All rights reserved.
5
*
6
* Copyright (c) 2016-2019 Netflix, Inc. written by M. Warner Losh
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
*
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
#include <stand.h>
31
32
#include <sys/disk.h>
33
#include <sys/param.h>
34
#include <sys/reboot.h>
35
#include <sys/boot.h>
36
#ifdef EFI_ZFS_BOOT
37
#include <sys/zfs_bootenv.h>
38
#endif
39
#include <paths.h>
40
#include <netinet/in.h>
41
#include <netinet/in_systm.h>
42
#include <stdint.h>
43
#include <string.h>
44
#include <setjmp.h>
45
#include <disk.h>
46
#include <dev_net.h>
47
#include <net.h>
48
#include <machine/_inttypes.h>
49
50
#include <efi.h>
51
#include <efilib.h>
52
#include <efichar.h>
53
#include <efirng.h>
54
55
#include <uuid.h>
56
57
#include <bootstrap.h>
58
#include <smbios.h>
59
60
#include <dev/random/fortuna.h>
61
#include <geom/eli/pkcs5v2.h>
62
63
#include "efizfs.h"
64
#include "framebuffer.h"
65
66
#include "platform/acfreebsd.h"
67
#include "acconfig.h"
68
#define ACPI_SYSTEM_XFACE
69
#include "actypes.h"
70
#include "actbl.h"
71
72
#include "loader_efi.h"
73
74
struct arch_switch archsw = { /* MI/MD interface boundary */
75
.arch_autoload = efi_autoload,
76
.arch_getdev = efi_getdev,
77
.arch_copyin = efi_copyin,
78
.arch_copyout = efi_copyout,
79
#if defined(__amd64__) || defined(__i386__)
80
.arch_hypervisor = x86_hypervisor,
81
#endif
82
.arch_readin = efi_readin,
83
.arch_zfs_probe = efi_zfs_probe,
84
};
85
86
EFI_GUID acpi = ACPI_TABLE_GUID;
87
EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
88
EFI_GUID devid = DEVICE_PATH_PROTOCOL;
89
EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
90
EFI_GUID mps = MPS_TABLE_GUID;
91
EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
92
EFI_GUID smbios = SMBIOS_TABLE_GUID;
93
EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
94
EFI_GUID dxe = DXE_SERVICES_TABLE_GUID;
95
EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
96
EFI_GUID lzmadecomp = LZMA_DECOMPRESSION_GUID;
97
EFI_GUID mpcore = ARM_MP_CORE_INFO_TABLE_GUID;
98
EFI_GUID esrt = ESRT_TABLE_GUID;
99
EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
100
EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
101
EFI_GUID fdtdtb = FDT_TABLE_GUID;
102
EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
103
104
/*
105
* Number of seconds to wait for a keystroke before exiting with failure
106
* in the event no currdev is found. -2 means always break, -1 means
107
* never break, 0 means poll once and then reboot, > 0 means wait for
108
* that many seconds. "fail_timeout" can be set in the environment as
109
* well.
110
*/
111
static int fail_timeout = 5;
112
113
/*
114
* Current boot variable
115
*/
116
UINT16 boot_current;
117
118
/*
119
* Image that we booted from.
120
*/
121
EFI_LOADED_IMAGE *boot_img;
122
123
/*
124
* RSDP base table.
125
*/
126
ACPI_TABLE_RSDP *rsdp;
127
128
static bool
129
has_keyboard(void)
130
{
131
EFI_STATUS status;
132
EFI_DEVICE_PATH *path;
133
EFI_HANDLE *hin, *hin_end, *walker;
134
UINTN sz;
135
bool retval = false;
136
137
/*
138
* Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
139
* do the typical dance to get the right sized buffer.
140
*/
141
sz = 0;
142
hin = NULL;
143
status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
144
if (status == EFI_BUFFER_TOO_SMALL) {
145
hin = (EFI_HANDLE *)malloc(sz);
146
status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
147
hin);
148
if (EFI_ERROR(status))
149
free(hin);
150
}
151
if (EFI_ERROR(status))
152
return retval;
153
154
/*
155
* Look at each of the handles. If it supports the device path protocol,
156
* use it to get the device path for this handle. Then see if that
157
* device path matches either the USB device path for keyboards or the
158
* legacy device path for keyboards.
159
*/
160
hin_end = &hin[sz / sizeof(*hin)];
161
for (walker = hin; walker < hin_end; walker++) {
162
status = OpenProtocolByHandle(*walker, &devid, (void **)&path);
163
if (EFI_ERROR(status))
164
continue;
165
166
while (!IsDevicePathEnd(path)) {
167
/*
168
* Check for the ACPI keyboard node. All PNP3xx nodes
169
* are keyboards of different flavors. Note: It is
170
* unclear of there's always a keyboard node when
171
* there's a keyboard controller, or if there's only one
172
* when a keyboard is detected at boot.
173
*/
174
if (DevicePathType(path) == ACPI_DEVICE_PATH &&
175
(DevicePathSubType(path) == ACPI_DP ||
176
DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
177
ACPI_HID_DEVICE_PATH *acpi;
178
179
acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
180
if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
181
(acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
182
retval = true;
183
goto out;
184
}
185
/*
186
* Check for USB keyboard node, if present. Unlike a
187
* PS/2 keyboard, these definitely only appear when
188
* connected to the system.
189
*/
190
} else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
191
DevicePathSubType(path) == MSG_USB_CLASS_DP) {
192
USB_CLASS_DEVICE_PATH *usb;
193
194
usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
195
if (usb->DeviceClass == 3 && /* HID */
196
usb->DeviceSubClass == 1 && /* Boot devices */
197
usb->DeviceProtocol == 1) { /* Boot keyboards */
198
retval = true;
199
goto out;
200
}
201
}
202
path = NextDevicePathNode(path);
203
}
204
}
205
out:
206
free(hin);
207
return retval;
208
}
209
210
static void
211
set_currdev_devdesc(struct devdesc *currdev)
212
{
213
const char *devname;
214
215
devname = devformat(currdev);
216
printf("Setting currdev to %s\n", devname);
217
set_currdev(devname);
218
}
219
220
static void
221
set_currdev_devsw(struct devsw *dev, int unit)
222
{
223
struct devdesc currdev;
224
225
currdev.d_dev = dev;
226
currdev.d_unit = unit;
227
228
set_currdev_devdesc(&currdev);
229
}
230
231
static void
232
set_currdev_pdinfo(pdinfo_t *dp)
233
{
234
235
/*
236
* Disks are special: they have partitions. if the parent
237
* pointer is non-null, we're a partition not a full disk
238
* and we need to adjust currdev appropriately.
239
*/
240
if (dp->pd_devsw->dv_type == DEVT_DISK) {
241
struct disk_devdesc currdev;
242
243
currdev.dd.d_dev = dp->pd_devsw;
244
if (dp->pd_parent == NULL) {
245
currdev.dd.d_unit = dp->pd_unit;
246
currdev.d_slice = D_SLICENONE;
247
currdev.d_partition = D_PARTNONE;
248
} else {
249
currdev.dd.d_unit = dp->pd_parent->pd_unit;
250
currdev.d_slice = dp->pd_unit;
251
currdev.d_partition = D_PARTISGPT; /* XXX Assumes GPT */
252
}
253
set_currdev_devdesc((struct devdesc *)&currdev);
254
} else {
255
set_currdev_devsw(dp->pd_devsw, dp->pd_unit);
256
}
257
}
258
259
static bool
260
sanity_check_currdev(void)
261
{
262
struct stat st;
263
264
return (stat(PATH_DEFAULTS_LOADER_CONF, &st) == 0 ||
265
#ifdef PATH_BOOTABLE_TOKEN
266
stat(PATH_BOOTABLE_TOKEN, &st) == 0 || /* non-standard layout */
267
#endif
268
stat(PATH_KERNEL, &st) == 0);
269
}
270
271
#ifdef EFI_ZFS_BOOT
272
static bool
273
probe_zfs_currdev(uint64_t guid)
274
{
275
char buf[VDEV_PAD_SIZE];
276
char *devname;
277
struct zfs_devdesc currdev;
278
279
currdev.dd.d_dev = &zfs_dev;
280
currdev.dd.d_unit = 0;
281
currdev.pool_guid = guid;
282
currdev.root_guid = 0;
283
devname = devformat(&currdev.dd);
284
set_currdev(devname);
285
printf("Setting currdev to %s\n", devname);
286
init_zfs_boot_options(devname);
287
288
if (zfs_get_bootonce(&currdev, OS_BOOTONCE, buf, sizeof(buf)) == 0) {
289
printf("zfs bootonce: %s\n", buf);
290
set_currdev(buf);
291
setenv("zfs-bootonce", buf, 1);
292
}
293
(void)zfs_attach_nvstore(&currdev);
294
295
return (sanity_check_currdev());
296
}
297
#endif
298
299
#ifdef MD_IMAGE_SIZE
300
extern struct devsw md_dev;
301
302
static bool
303
probe_md_currdev(void)
304
{
305
bool rv;
306
307
set_currdev_devsw(&md_dev, 0);
308
rv = sanity_check_currdev();
309
if (!rv)
310
printf("MD not present\n");
311
return (rv);
312
}
313
#endif
314
315
static bool
316
try_as_currdev(pdinfo_t *hd, pdinfo_t *pp)
317
{
318
uint64_t guid;
319
320
#ifdef EFI_ZFS_BOOT
321
/*
322
* If there's a zpool on this device, try it as a ZFS
323
* filesystem, which has somewhat different setup than all
324
* other types of fs due to imperfect loader integration.
325
* This all stems from ZFS being both a device (zpool) and
326
* a filesystem, plus the boot env feature.
327
*/
328
if (efizfs_get_guid_by_handle(pp->pd_handle, &guid))
329
return (probe_zfs_currdev(guid));
330
#endif
331
/*
332
* All other filesystems just need the pdinfo
333
* initialized in the standard way.
334
*/
335
set_currdev_pdinfo(pp);
336
return (sanity_check_currdev());
337
}
338
339
/*
340
* Sometimes we get filenames that are all upper case
341
* and/or have backslashes in them. Filter all this out
342
* if it looks like we need to do so.
343
*/
344
static void
345
fix_dosisms(char *p)
346
{
347
while (*p) {
348
if (isupper(*p))
349
*p = tolower(*p);
350
else if (*p == '\\')
351
*p = '/';
352
p++;
353
}
354
}
355
356
#define SIZE(dp, edp) (size_t)((intptr_t)(void *)edp - (intptr_t)(void *)dp)
357
358
enum { BOOT_INFO_OK = 0, BAD_CHOICE = 1, NOT_SPECIFIC = 2 };
359
static int
360
match_boot_info(char *boot_info, size_t bisz)
361
{
362
uint32_t attr;
363
uint16_t fplen;
364
size_t len;
365
char *walker, *ep;
366
EFI_DEVICE_PATH *dp, *edp, *first_dp, *last_dp;
367
pdinfo_t *pp;
368
CHAR16 *descr;
369
char *kernel = NULL;
370
FILEPATH_DEVICE_PATH *fp;
371
struct stat st;
372
CHAR16 *text;
373
374
/*
375
* FreeBSD encodes its boot loading path into the boot loader
376
* BootXXXX variable. We look for the last one in the path
377
* and use that to load the kernel. However, if we only find
378
* one DEVICE_PATH, then there's nothing specific and we should
379
* fall back.
380
*
381
* In an ideal world, we'd look at the image handle we were
382
* passed, match up with the loader we are and then return the
383
* next one in the path. This would be most flexible and cover
384
* many chain booting scenarios where you need to use this
385
* boot loader to get to the next boot loader. However, that
386
* doesn't work. We rarely have the path to the image booted
387
* (just the device) so we can't count on that. So, we do the
388
* next best thing: we look through the device path(s) passed
389
* in the BootXXXX variable. If there's only one, we return
390
* NOT_SPECIFIC. Otherwise, we look at the last one and try to
391
* load that. If we can, we return BOOT_INFO_OK. Otherwise we
392
* return BAD_CHOICE for the caller to sort out.
393
*/
394
if (bisz < sizeof(attr) + sizeof(fplen) + sizeof(CHAR16))
395
return NOT_SPECIFIC;
396
walker = boot_info;
397
ep = walker + bisz;
398
memcpy(&attr, walker, sizeof(attr));
399
walker += sizeof(attr);
400
memcpy(&fplen, walker, sizeof(fplen));
401
walker += sizeof(fplen);
402
descr = (CHAR16 *)(intptr_t)walker;
403
len = ucs2len(descr);
404
walker += (len + 1) * sizeof(CHAR16);
405
last_dp = first_dp = dp = (EFI_DEVICE_PATH *)walker;
406
edp = (EFI_DEVICE_PATH *)(walker + fplen);
407
if ((char *)edp > ep)
408
return NOT_SPECIFIC;
409
while (dp < edp && SIZE(dp, edp) > sizeof(EFI_DEVICE_PATH)) {
410
text = efi_devpath_name(dp);
411
if (text != NULL) {
412
printf(" BootInfo Path: %S\n", text);
413
efi_free_devpath_name(text);
414
}
415
last_dp = dp;
416
dp = (EFI_DEVICE_PATH *)((char *)dp + efi_devpath_length(dp));
417
}
418
419
/*
420
* If there's only one item in the list, then nothing was
421
* specified. Or if the last path doesn't have a media
422
* path in it. Those show up as various VenHw() nodes
423
* which are basically opaque to us. Don't count those
424
* as something specifc.
425
*/
426
if (last_dp == first_dp) {
427
printf("Ignoring Boot%04x: Only one DP found\n", boot_current);
428
return NOT_SPECIFIC;
429
}
430
if (efi_devpath_to_media_path(last_dp) == NULL) {
431
printf("Ignoring Boot%04x: No Media Path\n", boot_current);
432
return NOT_SPECIFIC;
433
}
434
435
/*
436
* OK. At this point we either have a good path or a bad one.
437
* Let's check.
438
*/
439
pp = efiblk_get_pdinfo_by_device_path(last_dp);
440
if (pp == NULL) {
441
printf("Ignoring Boot%04x: Device Path not found\n", boot_current);
442
return BAD_CHOICE;
443
}
444
set_currdev_pdinfo(pp);
445
if (!sanity_check_currdev()) {
446
printf("Ignoring Boot%04x: sanity check failed\n", boot_current);
447
return BAD_CHOICE;
448
}
449
450
/*
451
* OK. We've found a device that matches, next we need to check the last
452
* component of the path. If it's a file, then we set the default kernel
453
* to that. Otherwise, just use this as the default root.
454
*
455
* Reminder: we're running very early, before we've parsed the defaults
456
* file, so we may need to have a hack override.
457
*/
458
dp = efi_devpath_last_node(last_dp);
459
if (DevicePathType(dp) != MEDIA_DEVICE_PATH ||
460
DevicePathSubType(dp) != MEDIA_FILEPATH_DP) {
461
printf("Using Boot%04x for root partition\n", boot_current);
462
return (BOOT_INFO_OK); /* use currdir, default kernel */
463
}
464
fp = (FILEPATH_DEVICE_PATH *)dp;
465
ucs2_to_utf8(fp->PathName, &kernel);
466
if (kernel == NULL) {
467
printf("Not using Boot%04x: can't decode kernel\n", boot_current);
468
return (BAD_CHOICE);
469
}
470
if (*kernel == '\\' || isupper(*kernel))
471
fix_dosisms(kernel);
472
if (stat(kernel, &st) != 0) {
473
free(kernel);
474
printf("Not using Boot%04x: can't find %s\n", boot_current,
475
kernel);
476
return (BAD_CHOICE);
477
}
478
setenv("kernel", kernel, 1);
479
free(kernel);
480
text = efi_devpath_name(last_dp);
481
if (text) {
482
printf("Using Boot%04x %S + %s\n", boot_current, text,
483
kernel);
484
efi_free_devpath_name(text);
485
}
486
487
return (BOOT_INFO_OK);
488
}
489
490
/*
491
* Look at the passed-in boot_info, if any. If we find it then we need
492
* to see if we can find ourselves in the boot chain. If we can, and
493
* there's another specified thing to boot next, assume that the file
494
* is loaded from / and use that for the root filesystem. If can't
495
* find the specified thing, we must fail the boot. If we're last on
496
* the list, then we fallback to looking for the first available /
497
* candidate (ZFS, if there's a bootable zpool, otherwise a UFS
498
* partition that has either /boot/defaults/loader.conf on it or
499
* /boot/kernel/kernel (the default kernel) that we can use.
500
*
501
* We always fail if we can't find the right thing. However, as
502
* a concession to buggy UEFI implementations, like u-boot, if
503
* we have determined that the host is violating the UEFI boot
504
* manager protocol, we'll signal the rest of the program that
505
* a drop to the OK boot loader prompt is possible.
506
*/
507
static int
508
find_currdev(bool do_bootmgr, bool is_last,
509
char *boot_info, size_t boot_info_sz)
510
{
511
pdinfo_t *dp, *pp;
512
EFI_DEVICE_PATH *devpath, *copy;
513
EFI_HANDLE h;
514
CHAR16 *text;
515
struct devsw *dev;
516
int unit;
517
uint64_t extra;
518
int rv;
519
char *rootdev;
520
521
/*
522
* First choice: if rootdev is already set, use that, even if
523
* it's wrong.
524
*/
525
rootdev = getenv("rootdev");
526
if (rootdev != NULL && *rootdev != '\0') {
527
printf(" Setting currdev to configured rootdev %s\n",
528
rootdev);
529
set_currdev(rootdev);
530
return (0);
531
}
532
533
/*
534
* Second choice: If uefi_rootdev is set, translate that UEFI device
535
* path to the loader's internal name and use that.
536
*/
537
do {
538
rootdev = getenv("uefi_rootdev");
539
if (rootdev == NULL)
540
break;
541
devpath = efi_name_to_devpath(rootdev);
542
if (devpath == NULL)
543
break;
544
dp = efiblk_get_pdinfo_by_device_path(devpath);
545
efi_devpath_free(devpath);
546
if (dp == NULL)
547
break;
548
printf(" Setting currdev to UEFI path %s\n",
549
rootdev);
550
set_currdev_pdinfo(dp);
551
return (0);
552
} while (0);
553
554
/*
555
* Third choice: If we can find out image boot_info, and there's
556
* a follow-on boot image in that boot_info, use that. In this
557
* case root will be the partition specified in that image and
558
* we'll load the kernel specified by the file path. Should there
559
* not be a filepath, we use the default. This filepath overrides
560
* loader.conf.
561
*/
562
if (do_bootmgr) {
563
rv = match_boot_info(boot_info, boot_info_sz);
564
switch (rv) {
565
case BOOT_INFO_OK: /* We found it */
566
return (0);
567
case BAD_CHOICE: /* specified file not found -> error */
568
/* XXX do we want to have an escape hatch for last in boot order? */
569
return (ENOENT);
570
} /* Nothing specified, try normal match */
571
}
572
573
#ifdef EFI_ZFS_BOOT
574
/*
575
* Did efi_zfs_probe() detect the boot pool? If so, use the zpool
576
* it found, if it's sane. ZFS is the only thing that looks for
577
* disks and pools to boot. This may change in the future, however,
578
* if we allow specifying which pool to boot from via UEFI variables
579
* rather than the bootenv stuff that FreeBSD uses today.
580
*/
581
if (pool_guid != 0) {
582
printf("Trying ZFS pool\n");
583
if (probe_zfs_currdev(pool_guid))
584
return (0);
585
}
586
#endif /* EFI_ZFS_BOOT */
587
588
#ifdef MD_IMAGE_SIZE
589
/*
590
* If there is an embedded MD, try to use that.
591
*/
592
printf("Trying MD\n");
593
if (probe_md_currdev())
594
return (0);
595
#endif /* MD_IMAGE_SIZE */
596
597
/*
598
* Try to find the block device by its handle based on the
599
* image we're booting. If we can't find a sane partition,
600
* search all the other partitions of the disk. We do not
601
* search other disks because it's a violation of the UEFI
602
* boot protocol to do so. We fail and let UEFI go on to
603
* the next candidate.
604
*/
605
dp = efiblk_get_pdinfo_by_handle(boot_img->DeviceHandle);
606
if (dp != NULL) {
607
text = efi_devpath_name(dp->pd_devpath);
608
if (text != NULL) {
609
printf("Trying ESP: %S\n", text);
610
efi_free_devpath_name(text);
611
}
612
set_currdev_pdinfo(dp);
613
if (sanity_check_currdev())
614
return (0);
615
if (dp->pd_parent != NULL) {
616
pdinfo_t *espdp = dp;
617
dp = dp->pd_parent;
618
STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
619
/* Already tried the ESP */
620
if (espdp == pp)
621
continue;
622
/*
623
* Roll up the ZFS special case
624
* for those partitions that have
625
* zpools on them.
626
*/
627
text = efi_devpath_name(pp->pd_devpath);
628
if (text != NULL) {
629
printf("Trying: %S\n", text);
630
efi_free_devpath_name(text);
631
}
632
if (try_as_currdev(dp, pp))
633
return (0);
634
}
635
}
636
}
637
638
/*
639
* Try the device handle from our loaded image first. If that
640
* fails, use the device path from the loaded image and see if
641
* any of the nodes in that path match one of the enumerated
642
* handles. Currently, this handle list is only for netboot.
643
*/
644
if (efi_handle_lookup(boot_img->DeviceHandle, &dev, &unit, &extra) == 0) {
645
set_currdev_devsw(dev, unit);
646
if (sanity_check_currdev())
647
return (0);
648
}
649
650
copy = NULL;
651
devpath = efi_lookup_image_devpath(IH);
652
while (devpath != NULL) {
653
h = efi_devpath_handle(devpath);
654
if (h == NULL)
655
break;
656
657
free(copy);
658
copy = NULL;
659
660
if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
661
set_currdev_devsw(dev, unit);
662
if (sanity_check_currdev())
663
return (0);
664
}
665
666
devpath = efi_lookup_devpath(h);
667
if (devpath != NULL) {
668
copy = efi_devpath_trim(devpath);
669
devpath = copy;
670
}
671
}
672
free(copy);
673
674
return (ENOENT);
675
}
676
677
static bool
678
interactive_interrupt(const char *msg)
679
{
680
time_t now, then, last;
681
682
last = 0;
683
now = then = getsecs();
684
printf("%s\n", msg);
685
if (fail_timeout == -2) /* Always break to OK */
686
return (true);
687
if (fail_timeout == -1) /* Never break to OK */
688
return (false);
689
do {
690
if (last != now) {
691
printf("press any key to interrupt reboot in %d seconds\r",
692
fail_timeout - (int)(now - then));
693
last = now;
694
}
695
696
/* XXX no pause or timeout wait for char */
697
if (ischar())
698
return (true);
699
now = getsecs();
700
} while (now - then < fail_timeout);
701
return (false);
702
}
703
704
static int
705
parse_args(int argc, CHAR16 *argv[])
706
{
707
int i, howto;
708
char var[128];
709
710
/*
711
* Parse the args to set the console settings, etc
712
* boot1.efi passes these in, if it can read /boot.config or /boot/config
713
* or iPXE may be setup to pass these in. Or the optional argument in the
714
* boot environment was used to pass these arguments in (in which case
715
* neither /boot.config nor /boot/config are consulted).
716
*
717
* Loop through the args, and for each one that contains an '=' that is
718
* not the first character, add it to the environment. This allows
719
* loader and kernel env vars to be passed on the command line. Convert
720
* args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this
721
* method is flawed for non-ASCII characters).
722
*/
723
howto = 0;
724
for (i = 0; i < argc; i++) {
725
cpy16to8(argv[i], var, sizeof(var));
726
howto |= boot_parse_arg(var);
727
}
728
729
return (howto);
730
}
731
732
static void
733
setenv_int(const char *key, int val)
734
{
735
char buf[20];
736
737
snprintf(buf, sizeof(buf), "%d", val);
738
setenv(key, buf, 1);
739
}
740
741
static void *
742
acpi_map_sdt(vm_offset_t addr)
743
{
744
/* PA == VA */
745
return ((void *)addr);
746
}
747
748
static int
749
acpi_checksum(void *p, size_t length)
750
{
751
uint8_t *bp;
752
uint8_t sum;
753
754
bp = p;
755
sum = 0;
756
while (length--)
757
sum += *bp++;
758
759
return (sum);
760
}
761
762
static void *
763
acpi_find_table(uint8_t *sig)
764
{
765
int entries, i, addr_size;
766
ACPI_TABLE_HEADER *sdp;
767
ACPI_TABLE_RSDT *rsdt;
768
ACPI_TABLE_XSDT *xsdt;
769
vm_offset_t addr;
770
771
if (rsdp == NULL)
772
return (NULL);
773
774
rsdt = (ACPI_TABLE_RSDT *)(uintptr_t)rsdp->RsdtPhysicalAddress;
775
xsdt = (ACPI_TABLE_XSDT *)(uintptr_t)rsdp->XsdtPhysicalAddress;
776
if (rsdp->Revision < 2) {
777
sdp = (ACPI_TABLE_HEADER *)rsdt;
778
addr_size = sizeof(uint32_t);
779
} else {
780
sdp = (ACPI_TABLE_HEADER *)xsdt;
781
addr_size = sizeof(uint64_t);
782
}
783
entries = (sdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size;
784
for (i = 0; i < entries; i++) {
785
if (addr_size == 4)
786
addr = le32toh(rsdt->TableOffsetEntry[i]);
787
else
788
addr = le64toh(xsdt->TableOffsetEntry[i]);
789
if (addr == 0)
790
continue;
791
sdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr);
792
if (acpi_checksum(sdp, sdp->Length)) {
793
printf("RSDT entry %d (sig %.4s) is corrupt", i,
794
sdp->Signature);
795
continue;
796
}
797
if (memcmp(sig, sdp->Signature, 4) == 0)
798
return (sdp);
799
}
800
return (NULL);
801
}
802
803
/*
804
* Convert the InterfaceType in the SPCR. These are encoded the same for DBG2
805
* tables as well (though we don't parse those here).
806
*/
807
static const char *
808
acpi_uart_type(UINT8 t)
809
{
810
static const char *types[] = {
811
[0x00] = "ns8250", /* Full 16550 */
812
[0x01] = "ns8250", /* DBGP Rev 1 16550 subset */
813
[0x03] = "pl011", /* Arm PL011 */
814
[0x05] = "ns8250", /* Nvidia 16550 */
815
[0x0d] = "pl011", /* Arm SBSA 32-bit width */
816
[0x0e] = "pl011", /* Arm SBSA generic */
817
[0x12] = "ns8250", /* 16550 defined in SerialPort */
818
};
819
820
if (t >= nitems(types))
821
return (NULL);
822
return (types[t]);
823
}
824
825
static int
826
acpi_uart_baud(UINT8 b)
827
{
828
static int baud[] = { 0, -1, -1, 9600, 19200, -1, 57600, 115200 };
829
830
if (b > 7)
831
return (-1);
832
return (baud[b]);
833
}
834
835
static int
836
acpi_uart_regionwidth(UINT8 rw)
837
{
838
if (rw == 0)
839
return (1);
840
if (rw > 4)
841
return (-1);
842
return (1 << (rw - 1));
843
}
844
845
static const char *
846
acpi_uart_parity(UINT8 p)
847
{
848
/* Some of these SPCR entires get this wrong, hard wire none */
849
return ("none");
850
}
851
852
/*
853
* See if we can find a SPCR ACPI table in the static tables. If so, then it
854
* describes the serial console that's been redirected to, so we know that at
855
* least there's a serial console. this is most important for embedded systems
856
* that don't have traidtional PC serial ports.
857
*
858
* All the two letter variables in this function correspond to their usage in
859
* the uart(4) console string. We use io == -1 to select between I/O ports and
860
* memory mapped addresses. Set both hw.uart.console and hw.uart.consol.extra
861
* to communicate settings from SPCR to the kernel.
862
*/
863
static int
864
check_acpi_spcr(void)
865
{
866
ACPI_TABLE_SPCR *spcr;
867
int br, db, io, rs, rw, sb, xo, pv, pd;
868
uintmax_t mm;
869
const char *dt, *pa;
870
char *val = NULL;
871
872
spcr = acpi_find_table(ACPI_SIG_SPCR);
873
if (spcr == NULL)
874
return (0);
875
dt = acpi_uart_type(spcr->InterfaceType);
876
if (dt == NULL) { /* Kernel can't use unknown types */
877
printf("UART Type %d not known\n", spcr->InterfaceType);
878
return (0);
879
}
880
881
/* I/O vs Memory mapped vs PCI device */
882
io = -1;
883
pv = spcr->PciVendorId;
884
pd = spcr->PciDeviceId;
885
if (pv == 0xffff && pd == 0xffff) {
886
if (spcr->SerialPort.SpaceId == 1)
887
io = spcr->SerialPort.Address;
888
else {
889
mm = spcr->SerialPort.Address;
890
rs = ffs(spcr->SerialPort.BitWidth) - 4;
891
rw = acpi_uart_regionwidth(spcr->SerialPort.AccessWidth);
892
}
893
} else {
894
/* XXX todo: bus:device:function + flags and segment */
895
}
896
897
/* Uart settings */
898
pa = acpi_uart_parity(spcr->Parity);
899
sb = spcr->StopBits;
900
db = 8;
901
902
/*
903
* UartClkFreq is 3 and newer. We always use it then (it's only valid if
904
* it isn't 0, but if it is 0, we want to use 0 to have the kernel
905
* guess).
906
*/
907
if (spcr->Header.Revision <= 2)
908
xo = 0;
909
else
910
xo = spcr->UartClkFreq;
911
912
/*
913
* PreciseBaudrate, when non-zero, is to be preferred. It's only valid,
914
* though, for rev 4 and newer. So when it's 0 or the version is too
915
* old, we do the old-style table lookup. Otherwise we believe it.
916
*/
917
if (spcr->Header.Revision <= 3 || spcr->PreciseBaudrate == 0)
918
br = acpi_uart_baud(spcr->BaudRate);
919
else
920
br = spcr->PreciseBaudrate;
921
922
if (io != -1) {
923
asprintf(&val, "db:%d,dt:%s,io:%#x,pa:%s,br:%d,xo=%d",
924
db, dt, io, pa, br, xo);
925
} else if (pv != 0xffff && pd != 0xffff) {
926
asprintf(&val, "db:%d,dt:%s,pv:%#x,pd:%#x,pa:%s,br:%d,xo=%d",
927
db, dt, pv, pd, pa, br, xo);
928
} else {
929
asprintf(&val, "db:%d,dt:%s,mm:%#jx,rs:%d,rw:%d,pa:%s,br:%d,xo=%d",
930
db, dt, mm, rs, rw, pa, br, xo);
931
}
932
env_setenv("hw.uart.console", EV_VOLATILE, val, NULL, NULL);
933
free(val);
934
935
return (RB_SERIAL);
936
}
937
938
939
/*
940
* Parse ConOut (the list of consoles active) and see if we can find a serial
941
* port and/or a video port. It would be nice to also walk the ACPI DSDT to map
942
* the UID for the serial port to a port since there's no standard mapping. Also
943
* check for ConIn as well. This will be enough to determine if we have serial,
944
* and if we don't, we default to video. If there's a dual-console situation
945
* with only ConIn defined, this will currently fail.
946
*/
947
int
948
parse_uefi_con_out(void)
949
{
950
int how, rv;
951
int vid_seen = 0, com_seen = 0, seen = 0;
952
size_t sz;
953
char buf[4096], *ep;
954
EFI_DEVICE_PATH *node;
955
ACPI_HID_DEVICE_PATH *acpi;
956
UART_DEVICE_PATH *uart;
957
bool pci_pending;
958
959
/*
960
* A SPCR in the ACPI fixed tables documents a serial port used for the
961
* console. It may mirror a video console, or may be stand alone. If it
962
* is present, we return RB_SERIAL and will use it for the kernel.
963
*/
964
how = check_acpi_spcr();
965
sz = sizeof(buf);
966
rv = efi_global_getenv("ConOut", buf, &sz);
967
if (rv != EFI_SUCCESS)
968
rv = efi_global_getenv("ConOutDev", buf, &sz);
969
if (rv != EFI_SUCCESS)
970
rv = efi_global_getenv("ConIn", buf, &sz);
971
if (rv != EFI_SUCCESS) {
972
/*
973
* If we don't have any Con* variable use both. If we have GOP
974
* make video primary, otherwise set serial primary. In either
975
* case, try to use both the 'efi' console which will use the
976
* GOP, if present and serial. If there's an EFI BIOS that omits
977
* this, but has a serial port redirect, we'll unavioidably get
978
* doubled characters, but we'll be right in all the other more
979
* common cases.
980
*/
981
if (efi_has_gop())
982
how |= RB_MULTIPLE;
983
else
984
how |= RB_MULTIPLE | RB_SERIAL;
985
setenv("console", "efi,comconsole", 1);
986
goto out;
987
}
988
ep = buf + sz;
989
node = (EFI_DEVICE_PATH *)buf;
990
while ((char *)node < ep) {
991
if (IsDevicePathEndType(node)) {
992
if (pci_pending && vid_seen == 0)
993
vid_seen = ++seen;
994
}
995
pci_pending = false;
996
if (DevicePathType(node) == ACPI_DEVICE_PATH &&
997
(DevicePathSubType(node) == ACPI_DP ||
998
DevicePathSubType(node) == ACPI_EXTENDED_DP)) {
999
/* Check for Serial node */
1000
acpi = (void *)node;
1001
if (EISA_ID_TO_NUM(acpi->HID) == 0x501) {
1002
setenv_int("efi_8250_uid", acpi->UID);
1003
com_seen = ++seen;
1004
}
1005
} else if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
1006
DevicePathSubType(node) == MSG_UART_DP) {
1007
com_seen = ++seen;
1008
uart = (void *)node;
1009
setenv_int("efi_com_speed", uart->BaudRate);
1010
} else if (DevicePathType(node) == ACPI_DEVICE_PATH &&
1011
DevicePathSubType(node) == ACPI_ADR_DP) {
1012
/* Check for AcpiAdr() Node for video */
1013
vid_seen = ++seen;
1014
} else if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
1015
DevicePathSubType(node) == HW_PCI_DP) {
1016
/*
1017
* Note, vmware fusion has a funky console device
1018
* PciRoot(0x0)/Pci(0xf,0x0)
1019
* which we can only detect at the end since we also
1020
* have to cope with:
1021
* PciRoot(0x0)/Pci(0x1f,0x0)/Serial(0x1)
1022
* so only match it if it's last.
1023
*/
1024
pci_pending = true;
1025
}
1026
node = NextDevicePathNode(node);
1027
}
1028
1029
/*
1030
* Truth table for RB_MULTIPLE | RB_SERIAL
1031
* Value Result
1032
* 0 Use only video console
1033
* RB_SERIAL Use only serial console
1034
* RB_MULTIPLE Use both video and serial console
1035
* (but video is primary so gets rc messages)
1036
* both Use both video and serial console
1037
* (but serial is primary so gets rc messages)
1038
*
1039
* Try to honor this as best we can. If only one of serial / video
1040
* found, then use that. Otherwise, use the first one we found.
1041
* This also implies if we found nothing, default to video.
1042
*/
1043
how = 0;
1044
if (vid_seen && com_seen) {
1045
how |= RB_MULTIPLE;
1046
if (com_seen < vid_seen)
1047
how |= RB_SERIAL;
1048
} else if (com_seen)
1049
how |= RB_SERIAL;
1050
out:
1051
return (how);
1052
}
1053
1054
void
1055
parse_loader_efi_config(EFI_HANDLE h, const char *env_fn)
1056
{
1057
pdinfo_t *dp;
1058
struct stat st;
1059
int fd = -1;
1060
char *env = NULL;
1061
1062
dp = efiblk_get_pdinfo_by_handle(h);
1063
if (dp == NULL)
1064
return;
1065
set_currdev_pdinfo(dp);
1066
if (stat(env_fn, &st) != 0)
1067
return;
1068
fd = open(env_fn, O_RDONLY);
1069
if (fd == -1)
1070
return;
1071
env = malloc(st.st_size + 1);
1072
if (env == NULL)
1073
goto out;
1074
if (read(fd, env, st.st_size) != st.st_size)
1075
goto out;
1076
env[st.st_size] = '\0';
1077
boot_parse_cmdline(env);
1078
out:
1079
free(env);
1080
close(fd);
1081
}
1082
1083
static void
1084
read_loader_env(const char *name, char *def_fn, bool once)
1085
{
1086
UINTN len;
1087
char *fn, *freeme = NULL;
1088
1089
len = 0;
1090
fn = def_fn;
1091
if (efi_freebsd_getenv(name, NULL, &len) == EFI_BUFFER_TOO_SMALL) {
1092
freeme = fn = malloc(len + 1);
1093
if (fn != NULL) {
1094
if (efi_freebsd_getenv(name, fn, &len) != EFI_SUCCESS) {
1095
free(fn);
1096
fn = NULL;
1097
printf(
1098
"Can't fetch FreeBSD::%s we know is there\n", name);
1099
} else {
1100
/*
1101
* if tagged as 'once' delete the env variable so we
1102
* only use it once.
1103
*/
1104
if (once)
1105
efi_freebsd_delenv(name);
1106
/*
1107
* We malloced 1 more than len above, then redid the call.
1108
* so now we have room at the end of the string to NUL terminate
1109
* it here, even if the typical idium would have '- 1' here to
1110
* not overflow. len should be the same on return both times.
1111
*/
1112
fn[len] = '\0';
1113
}
1114
} else {
1115
printf(
1116
"Can't allocate %d bytes to fetch FreeBSD::%s env var\n",
1117
len, name);
1118
}
1119
}
1120
if (fn) {
1121
printf(" Reading loader env vars from %s\n", fn);
1122
parse_loader_efi_config(boot_img->DeviceHandle, fn);
1123
}
1124
}
1125
1126
caddr_t
1127
ptov(uintptr_t x)
1128
{
1129
return ((caddr_t)x);
1130
}
1131
1132
static void
1133
acpi_detect(void)
1134
{
1135
char buf[24];
1136
int revision;
1137
1138
feature_enable(FEATURE_EARLY_ACPI);
1139
if ((rsdp = efi_get_table(&acpi20)) == NULL)
1140
if ((rsdp = efi_get_table(&acpi)) == NULL)
1141
return;
1142
1143
sprintf(buf, "0x%016"PRIxPTR, (uintptr_t)rsdp);
1144
setenv("acpi.rsdp", buf, 1);
1145
revision = rsdp->Revision;
1146
if (revision == 0)
1147
revision = 1;
1148
sprintf(buf, "%d", revision);
1149
setenv("acpi.revision", buf, 1);
1150
strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
1151
buf[sizeof(rsdp->OemId)] = '\0';
1152
setenv("acpi.oem", buf, 1);
1153
sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress);
1154
setenv("acpi.rsdt", buf, 1);
1155
if (revision >= 2) {
1156
/* XXX extended checksum? */
1157
sprintf(buf, "0x%016llx",
1158
(unsigned long long)rsdp->XsdtPhysicalAddress);
1159
setenv("acpi.xsdt", buf, 1);
1160
sprintf(buf, "%d", rsdp->Length);
1161
setenv("acpi.xsdt_length", buf, 1);
1162
}
1163
}
1164
1165
static void
1166
efi_smbios_detect(void)
1167
{
1168
VOID *smbios_v2_ptr = NULL;
1169
UINTN k;
1170
1171
for (k = 0; k < ST->NumberOfTableEntries; k++) {
1172
EFI_GUID *guid;
1173
VOID *const VT = ST->ConfigurationTable[k].VendorTable;
1174
char buf[40];
1175
bool is_smbios_v2, is_smbios_v3;
1176
1177
guid = &ST->ConfigurationTable[k].VendorGuid;
1178
is_smbios_v2 = memcmp(guid, &smbios, sizeof(*guid)) == 0;
1179
is_smbios_v3 = memcmp(guid, &smbios3, sizeof(*guid)) == 0;
1180
1181
if (!is_smbios_v2 && !is_smbios_v3)
1182
continue;
1183
1184
snprintf(buf, sizeof(buf), "%p", VT);
1185
setenv("hint.smbios.0.mem", buf, 1);
1186
if (is_smbios_v2)
1187
/*
1188
* We will parse a v2 table only if we don't find a v3
1189
* table. In the meantime, store the address.
1190
*/
1191
smbios_v2_ptr = VT;
1192
else if (smbios_detect(VT) != NULL)
1193
/* v3 parsing succeeded, we are done. */
1194
return;
1195
}
1196
if (smbios_v2_ptr != NULL)
1197
(void)smbios_detect(smbios_v2_ptr);
1198
}
1199
1200
EFI_STATUS
1201
main(int argc, CHAR16 *argv[])
1202
{
1203
int howto, i, uhowto;
1204
bool has_kbd, is_last;
1205
char *s;
1206
EFI_DEVICE_PATH *imgpath;
1207
CHAR16 *text;
1208
EFI_STATUS rv;
1209
size_t sz, bosz = 0, bisz = 0;
1210
UINT16 boot_order[100];
1211
char boot_info[4096];
1212
char buf[32];
1213
bool uefi_boot_mgr;
1214
1215
#if !defined(__arm__)
1216
efi_smbios_detect();
1217
#endif
1218
1219
/* Get our loaded image protocol interface structure. */
1220
(void) OpenProtocolByHandle(IH, &imgid, (void **)&boot_img);
1221
1222
/* Report the RSDP early. */
1223
acpi_detect();
1224
1225
/*
1226
* Chicken-and-egg problem; we want to have console output early, but
1227
* some console attributes may depend on reading from eg. the boot
1228
* device, which we can't do yet. We can use printf() etc. once this is
1229
* done. So, we set it to the efi console, then call console init. This
1230
* gets us printf early, but also primes the pump for all future console
1231
* changes to take effect, regardless of where they come from.
1232
*/
1233
setenv("console", "efi", 1);
1234
uhowto = parse_uefi_con_out();
1235
#if defined(__riscv)
1236
/*
1237
* This workaround likely is papering over a real issue
1238
*/
1239
if ((uhowto & RB_SERIAL) != 0)
1240
setenv("console", "comconsole", 1);
1241
#endif
1242
cons_probe();
1243
1244
/* Set print_delay variable to have hooks in place. */
1245
env_setenv("print_delay", EV_VOLATILE, "", setprint_delay, env_nounset);
1246
1247
/* Set up currdev variable to have hooks in place. */
1248
env_setenv("currdev", EV_VOLATILE, "", gen_setcurrdev, env_nounset);
1249
1250
/* Init the time source */
1251
efi_time_init();
1252
1253
/*
1254
* Initialise the block cache. Set the upper limit.
1255
*/
1256
bcache_init(32768, 512);
1257
1258
/*
1259
* Scan the BLOCK IO MEDIA handles then
1260
* march through the device switch probing for things.
1261
*/
1262
i = efipart_inithandles();
1263
if (i != 0 && i != ENOENT) {
1264
printf("efipart_inithandles failed with ERRNO %d, expect "
1265
"failures\n", i);
1266
}
1267
1268
devinit();
1269
1270
/*
1271
* Detect console settings two different ways: one via the command
1272
* args (eg -h) or via the UEFI ConOut variable.
1273
*/
1274
has_kbd = has_keyboard();
1275
howto = parse_args(argc, argv);
1276
if (!has_kbd && (howto & RB_PROBE))
1277
howto |= RB_SERIAL | RB_MULTIPLE;
1278
howto &= ~RB_PROBE;
1279
1280
/*
1281
* Read additional environment variables from the boot device's
1282
* "LoaderEnv" file. Any boot loader environment variable may be set
1283
* there, which are subtly different than loader.conf variables. Only
1284
* the 'simple' ones may be set so things like foo_load="YES" won't work
1285
* for two reasons. First, the parser is simplistic and doesn't grok
1286
* quotes. Second, because the variables that cause an action to happen
1287
* are parsed by the lua, 4th or whatever code that's not yet
1288
* loaded. This is relative to the root directory when loader.efi is
1289
* loaded off the UFS root drive (when chain booted), or from the ESP
1290
* when directly loaded by the BIOS.
1291
*
1292
* We also read in NextLoaderEnv if it was specified. This allows next boot
1293
* functionality to be implemented and to override anything in LoaderEnv.
1294
*/
1295
read_loader_env("LoaderEnv", "/efi/freebsd/loader.env", false);
1296
read_loader_env("NextLoaderEnv", NULL, true);
1297
1298
/*
1299
* We now have two notions of console. howto should be viewed as
1300
* overrides. If console is already set, don't set it again.
1301
*/
1302
#define VIDEO_ONLY 0
1303
#define SERIAL_ONLY RB_SERIAL
1304
#define VID_SER_BOTH RB_MULTIPLE
1305
#define SER_VID_BOTH (RB_SERIAL | RB_MULTIPLE)
1306
#define CON_MASK (RB_SERIAL | RB_MULTIPLE)
1307
if (strcmp(getenv("console"), "efi") == 0) {
1308
if ((howto & CON_MASK) == 0) {
1309
/* No override, uhowto is controlling and efi cons is perfect */
1310
howto = howto | (uhowto & CON_MASK);
1311
} else if ((howto & CON_MASK) == (uhowto & CON_MASK)) {
1312
/* override matches what UEFI told us, efi console is perfect */
1313
} else if ((uhowto & (CON_MASK)) != 0) {
1314
/*
1315
* We detected a serial console on ConOut. All possible
1316
* overrides include serial. We can't really override what efi
1317
* gives us, so we use it knowing it's the best choice.
1318
*/
1319
/* Do nothing */
1320
} else {
1321
/*
1322
* We detected some kind of serial in the override, but ConOut
1323
* has no serial, so we have to sort out which case it really is.
1324
*/
1325
switch (howto & CON_MASK) {
1326
case SERIAL_ONLY:
1327
setenv("console", "comconsole", 1);
1328
break;
1329
case VID_SER_BOTH:
1330
setenv("console", "efi comconsole", 1);
1331
break;
1332
case SER_VID_BOTH:
1333
setenv("console", "comconsole efi", 1);
1334
break;
1335
/* case VIDEO_ONLY can't happen -- it's the first if above */
1336
}
1337
}
1338
}
1339
1340
/*
1341
* howto is set now how we want to export the flags to the kernel, so
1342
* set the env based on it.
1343
*/
1344
boot_howto_to_env(howto);
1345
1346
if (efi_copy_init())
1347
return (EFI_BUFFER_TOO_SMALL);
1348
1349
if ((s = getenv("fail_timeout")) != NULL)
1350
fail_timeout = strtol(s, NULL, 10);
1351
1352
printf("%s\n", bootprog_info);
1353
printf(" Command line arguments:");
1354
for (i = 0; i < argc; i++)
1355
printf(" %S", argv[i]);
1356
printf("\n");
1357
1358
printf(" Image base: 0x%lx\n", (unsigned long)boot_img->ImageBase);
1359
printf(" EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
1360
ST->Hdr.Revision & 0xffff);
1361
printf(" EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
1362
ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
1363
printf(" Console: %s (%#x)\n", getenv("console"), howto);
1364
1365
/* Determine the devpath of our image so we can prefer it. */
1366
text = efi_devpath_name(boot_img->FilePath);
1367
if (text != NULL) {
1368
printf(" Load Path: %S\n", text);
1369
efi_setenv_freebsd_wcs("LoaderPath", text);
1370
efi_free_devpath_name(text);
1371
}
1372
1373
rv = OpenProtocolByHandle(boot_img->DeviceHandle, &devid,
1374
(void **)&imgpath);
1375
if (rv == EFI_SUCCESS) {
1376
text = efi_devpath_name(imgpath);
1377
if (text != NULL) {
1378
printf(" Load Device: %S\n", text);
1379
efi_setenv_freebsd_wcs("LoaderDev", text);
1380
efi_free_devpath_name(text);
1381
}
1382
}
1383
1384
if (getenv("uefi_ignore_boot_mgr") != NULL) {
1385
printf(" Ignoring UEFI boot manager\n");
1386
uefi_boot_mgr = false;
1387
} else {
1388
uefi_boot_mgr = true;
1389
boot_current = 0;
1390
sz = sizeof(boot_current);
1391
rv = efi_global_getenv("BootCurrent", &boot_current, &sz);
1392
if (rv == EFI_SUCCESS)
1393
printf(" BootCurrent: %04x\n", boot_current);
1394
else {
1395
boot_current = 0xffff;
1396
uefi_boot_mgr = false;
1397
}
1398
1399
sz = sizeof(boot_order);
1400
rv = efi_global_getenv("BootOrder", &boot_order, &sz);
1401
if (rv == EFI_SUCCESS) {
1402
printf(" BootOrder:");
1403
for (i = 0; i < sz / sizeof(boot_order[0]); i++)
1404
printf(" %04x%s", boot_order[i],
1405
boot_order[i] == boot_current ? "[*]" : "");
1406
printf("\n");
1407
is_last = boot_order[(sz / sizeof(boot_order[0])) - 1] == boot_current;
1408
bosz = sz;
1409
} else if (uefi_boot_mgr) {
1410
/*
1411
* u-boot doesn't set BootOrder, but otherwise participates in the
1412
* boot manager protocol. So we fake it here and don't consider it
1413
* a failure.
1414
*/
1415
bosz = sizeof(boot_order[0]);
1416
boot_order[0] = boot_current;
1417
is_last = true;
1418
}
1419
}
1420
1421
/*
1422
* Next, find the boot info structure the UEFI boot manager is
1423
* supposed to setup. We need this so we can walk through it to
1424
* find where we are in the booting process and what to try to
1425
* boot next.
1426
*/
1427
if (uefi_boot_mgr) {
1428
snprintf(buf, sizeof(buf), "Boot%04X", boot_current);
1429
sz = sizeof(boot_info);
1430
rv = efi_global_getenv(buf, &boot_info, &sz);
1431
if (rv == EFI_SUCCESS)
1432
bisz = sz;
1433
else
1434
uefi_boot_mgr = false;
1435
}
1436
1437
/*
1438
* Disable the watchdog timer. By default the boot manager sets
1439
* the timer to 5 minutes before invoking a boot option. If we
1440
* want to return to the boot manager, we have to disable the
1441
* watchdog timer and since we're an interactive program, we don't
1442
* want to wait until the user types "quit". The timer may have
1443
* fired by then. We don't care if this fails. It does not prevent
1444
* normal functioning in any way...
1445
*/
1446
BS->SetWatchdogTimer(0, 0, 0, NULL);
1447
1448
/*
1449
* Initialize the trusted/forbidden certificates from UEFI.
1450
* They will be later used to verify the manifest(s),
1451
* which should contain hashes of verified files.
1452
* This needs to be initialized before any configuration files
1453
* are loaded.
1454
*/
1455
#ifdef EFI_SECUREBOOT
1456
ve_efi_init();
1457
#endif
1458
1459
/*
1460
* Try and find a good currdev based on the image that was booted.
1461
* It might be desirable here to have a short pause to allow falling
1462
* through to the boot loader instead of returning instantly to follow
1463
* the boot protocol and also allow an escape hatch for users wishing
1464
* to try something different.
1465
*/
1466
if (find_currdev(uefi_boot_mgr, is_last, boot_info, bisz) != 0)
1467
if (uefi_boot_mgr &&
1468
!interactive_interrupt("Failed to find bootable partition"))
1469
return (EFI_NOT_FOUND);
1470
1471
autoload_font(false); /* Set up the font list for console. */
1472
efi_init_environment();
1473
1474
interact(); /* doesn't return */
1475
1476
return (EFI_SUCCESS); /* keep compiler happy */
1477
}
1478
1479
COMMAND_SET(efi_seed_entropy, "efi-seed-entropy", "try to get entropy from the EFI RNG", command_seed_entropy);
1480
1481
static int
1482
command_seed_entropy(int argc, char *argv[])
1483
{
1484
EFI_STATUS status;
1485
EFI_RNG_PROTOCOL *rng;
1486
unsigned int size_efi = RANDOM_FORTUNA_DEFPOOLSIZE * RANDOM_FORTUNA_NPOOLS;
1487
unsigned int size = RANDOM_FORTUNA_DEFPOOLSIZE * RANDOM_FORTUNA_NPOOLS;
1488
void *buf_efi;
1489
void *buf;
1490
1491
if (argc > 1) {
1492
size_efi = strtol(argv[1], NULL, 0);
1493
1494
/* Don't *compress* the entropy we get from EFI. */
1495
if (size_efi > size)
1496
size = size_efi;
1497
1498
/*
1499
* If the amount of entropy we get from EFI is less than the
1500
* size of a single Fortuna pool -- i.e. not enough to ensure
1501
* that Fortuna is safely seeded -- don't expand it since we
1502
* don't want to trick Fortuna into thinking that it has been
1503
* safely seeded when it has not.
1504
*/
1505
if (size_efi < RANDOM_FORTUNA_DEFPOOLSIZE)
1506
size = size_efi;
1507
}
1508
1509
status = BS->LocateProtocol(&rng_guid, NULL, (VOID **)&rng);
1510
if (status != EFI_SUCCESS) {
1511
command_errmsg = "RNG protocol not found";
1512
return (CMD_ERROR);
1513
}
1514
1515
if ((buf = malloc(size)) == NULL) {
1516
command_errmsg = "out of memory";
1517
return (CMD_ERROR);
1518
}
1519
1520
if ((buf_efi = malloc(size_efi)) == NULL) {
1521
free(buf);
1522
command_errmsg = "out of memory";
1523
return (CMD_ERROR);
1524
}
1525
1526
TSENTER2("rng->GetRNG");
1527
status = rng->GetRNG(rng, NULL, size_efi, (UINT8 *)buf_efi);
1528
TSEXIT();
1529
if (status != EFI_SUCCESS) {
1530
free(buf_efi);
1531
free(buf);
1532
command_errmsg = "GetRNG failed";
1533
return (CMD_ERROR);
1534
}
1535
if (size_efi < size)
1536
pkcs5v2_genkey_raw(buf, size, "", 0, buf_efi, size_efi, 1);
1537
else
1538
memcpy(buf, buf_efi, size);
1539
1540
if (file_addbuf("efi_rng_seed", "boot_entropy_platform", size, buf) != 0) {
1541
free(buf_efi);
1542
free(buf);
1543
return (CMD_ERROR);
1544
}
1545
1546
explicit_bzero(buf_efi, size_efi);
1547
free(buf_efi);
1548
free(buf);
1549
return (CMD_OK);
1550
}
1551
1552
COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff);
1553
COMMAND_SET(halt, "halt", "power off the system", command_poweroff);
1554
1555
static int
1556
command_poweroff(int argc __unused, char *argv[] __unused)
1557
{
1558
int i;
1559
1560
for (i = 0; devsw[i] != NULL; ++i)
1561
if (devsw[i]->dv_cleanup != NULL)
1562
(devsw[i]->dv_cleanup)();
1563
1564
RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1565
1566
/* NOTREACHED */
1567
return (CMD_ERROR);
1568
}
1569
1570
COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
1571
1572
static int
1573
command_reboot(int argc, char *argv[])
1574
{
1575
int i;
1576
1577
for (i = 0; devsw[i] != NULL; ++i)
1578
if (devsw[i]->dv_cleanup != NULL)
1579
(devsw[i]->dv_cleanup)();
1580
1581
RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1582
1583
/* NOTREACHED */
1584
return (CMD_ERROR);
1585
}
1586
1587
COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
1588
1589
static int
1590
command_memmap(int argc __unused, char *argv[] __unused)
1591
{
1592
UINTN sz;
1593
EFI_MEMORY_DESCRIPTOR *map, *p;
1594
UINTN key, dsz;
1595
UINT32 dver;
1596
EFI_STATUS status;
1597
int i, ndesc;
1598
char line[80];
1599
1600
sz = 0;
1601
status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
1602
if (status != EFI_BUFFER_TOO_SMALL) {
1603
printf("Can't determine memory map size\n");
1604
return (CMD_ERROR);
1605
}
1606
map = malloc(sz);
1607
status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
1608
if (EFI_ERROR(status)) {
1609
printf("Can't read memory map\n");
1610
return (CMD_ERROR);
1611
}
1612
1613
ndesc = sz / dsz;
1614
snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n",
1615
"Type", "Physical", "Virtual", "#Pages", "Attr");
1616
pager_open();
1617
if (pager_output(line)) {
1618
pager_close();
1619
return (CMD_OK);
1620
}
1621
1622
for (i = 0, p = map; i < ndesc;
1623
i++, p = NextMemoryDescriptor(p, dsz)) {
1624
snprintf(line, sizeof(line), "%23s %012jx %012jx %08jx ",
1625
efi_memory_type(p->Type), (uintmax_t)p->PhysicalStart,
1626
(uintmax_t)p->VirtualStart, (uintmax_t)p->NumberOfPages);
1627
if (pager_output(line))
1628
break;
1629
1630
if (p->Attribute & EFI_MEMORY_UC)
1631
printf("UC ");
1632
if (p->Attribute & EFI_MEMORY_WC)
1633
printf("WC ");
1634
if (p->Attribute & EFI_MEMORY_WT)
1635
printf("WT ");
1636
if (p->Attribute & EFI_MEMORY_WB)
1637
printf("WB ");
1638
if (p->Attribute & EFI_MEMORY_UCE)
1639
printf("UCE ");
1640
if (p->Attribute & EFI_MEMORY_WP)
1641
printf("WP ");
1642
if (p->Attribute & EFI_MEMORY_RP)
1643
printf("RP ");
1644
if (p->Attribute & EFI_MEMORY_XP)
1645
printf("XP ");
1646
if (p->Attribute & EFI_MEMORY_NV)
1647
printf("NV ");
1648
if (p->Attribute & EFI_MEMORY_MORE_RELIABLE)
1649
printf("MR ");
1650
if (p->Attribute & EFI_MEMORY_RO)
1651
printf("RO ");
1652
if (pager_output("\n"))
1653
break;
1654
}
1655
1656
pager_close();
1657
return (CMD_OK);
1658
}
1659
1660
COMMAND_SET(configuration, "configuration", "print configuration tables",
1661
command_configuration);
1662
1663
static int
1664
command_configuration(int argc, char *argv[])
1665
{
1666
UINTN i;
1667
char *name;
1668
1669
printf("NumberOfTableEntries=%lu\n",
1670
(unsigned long)ST->NumberOfTableEntries);
1671
1672
for (i = 0; i < ST->NumberOfTableEntries; i++) {
1673
EFI_GUID *guid;
1674
1675
printf(" ");
1676
guid = &ST->ConfigurationTable[i].VendorGuid;
1677
1678
if (efi_guid_to_name(guid, &name) == true) {
1679
printf(name);
1680
free(name);
1681
} else {
1682
printf("Error while translating UUID to name");
1683
}
1684
printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
1685
}
1686
1687
return (CMD_OK);
1688
}
1689
1690
1691
COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
1692
1693
static int
1694
command_mode(int argc, char *argv[])
1695
{
1696
UINTN cols, rows;
1697
unsigned int mode;
1698
int i;
1699
char *cp;
1700
EFI_STATUS status;
1701
SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
1702
1703
conout = ST->ConOut;
1704
1705
if (argc > 1) {
1706
mode = strtol(argv[1], &cp, 0);
1707
if (cp[0] != '\0') {
1708
printf("Invalid mode\n");
1709
return (CMD_ERROR);
1710
}
1711
status = conout->QueryMode(conout, mode, &cols, &rows);
1712
if (EFI_ERROR(status)) {
1713
printf("invalid mode %d\n", mode);
1714
return (CMD_ERROR);
1715
}
1716
status = conout->SetMode(conout, mode);
1717
if (EFI_ERROR(status)) {
1718
printf("couldn't set mode %d\n", mode);
1719
return (CMD_ERROR);
1720
}
1721
(void) cons_update_mode(true);
1722
return (CMD_OK);
1723
}
1724
1725
printf("Current mode: %d\n", conout->Mode->Mode);
1726
for (i = 0; i <= conout->Mode->MaxMode; i++) {
1727
status = conout->QueryMode(conout, i, &cols, &rows);
1728
if (EFI_ERROR(status))
1729
continue;
1730
printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
1731
(unsigned)rows);
1732
}
1733
1734
if (i != 0)
1735
printf("Select a mode with the command \"mode <number>\"\n");
1736
1737
return (CMD_OK);
1738
}
1739
1740
COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
1741
1742
static void
1743
lsefi_print_handle_info(EFI_HANDLE handle)
1744
{
1745
EFI_DEVICE_PATH *devpath;
1746
EFI_DEVICE_PATH *imagepath;
1747
CHAR16 *dp_name;
1748
1749
imagepath = efi_lookup_image_devpath(handle);
1750
if (imagepath != NULL) {
1751
dp_name = efi_devpath_name(imagepath);
1752
printf("Handle for image %S", dp_name);
1753
efi_free_devpath_name(dp_name);
1754
return;
1755
}
1756
devpath = efi_lookup_devpath(handle);
1757
if (devpath != NULL) {
1758
dp_name = efi_devpath_name(devpath);
1759
printf("Handle for device %S", dp_name);
1760
efi_free_devpath_name(dp_name);
1761
return;
1762
}
1763
printf("Handle %p", handle);
1764
}
1765
1766
static int
1767
command_lsefi(int argc __unused, char *argv[] __unused)
1768
{
1769
char *name;
1770
EFI_HANDLE *buffer = NULL;
1771
EFI_HANDLE handle;
1772
UINTN bufsz = 0, i, j;
1773
EFI_STATUS status;
1774
int ret = 0;
1775
1776
status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
1777
if (status != EFI_BUFFER_TOO_SMALL) {
1778
snprintf(command_errbuf, sizeof (command_errbuf),
1779
"unexpected error: %lld", (long long)status);
1780
return (CMD_ERROR);
1781
}
1782
if ((buffer = malloc(bufsz)) == NULL) {
1783
sprintf(command_errbuf, "out of memory");
1784
return (CMD_ERROR);
1785
}
1786
1787
status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
1788
if (EFI_ERROR(status)) {
1789
free(buffer);
1790
snprintf(command_errbuf, sizeof (command_errbuf),
1791
"LocateHandle() error: %lld", (long long)status);
1792
return (CMD_ERROR);
1793
}
1794
1795
pager_open();
1796
for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
1797
UINTN nproto = 0;
1798
EFI_GUID **protocols = NULL;
1799
1800
handle = buffer[i];
1801
lsefi_print_handle_info(handle);
1802
if (pager_output("\n"))
1803
break;
1804
/* device path */
1805
1806
status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
1807
if (EFI_ERROR(status)) {
1808
snprintf(command_errbuf, sizeof (command_errbuf),
1809
"ProtocolsPerHandle() error: %lld",
1810
(long long)status);
1811
continue;
1812
}
1813
1814
for (j = 0; j < nproto; j++) {
1815
if (efi_guid_to_name(protocols[j], &name) == true) {
1816
printf(" %s", name);
1817
free(name);
1818
} else {
1819
printf("Error while translating UUID to name");
1820
}
1821
if ((ret = pager_output("\n")) != 0)
1822
break;
1823
}
1824
BS->FreePool(protocols);
1825
if (ret != 0)
1826
break;
1827
}
1828
pager_close();
1829
free(buffer);
1830
return (CMD_OK);
1831
}
1832
1833
#ifdef LOADER_FDT_SUPPORT
1834
extern int command_fdt_internal(int argc, char *argv[]);
1835
1836
/*
1837
* Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1838
* and declaring it as extern is in contradiction with COMMAND_SET() macro
1839
* (which uses static pointer), we're defining wrapper function, which
1840
* calls the proper fdt handling routine.
1841
*/
1842
static int
1843
command_fdt(int argc, char *argv[])
1844
{
1845
1846
return (command_fdt_internal(argc, argv));
1847
}
1848
1849
COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
1850
#endif
1851
1852
/*
1853
* Chain load another efi loader.
1854
*/
1855
static int
1856
command_chain(int argc, char *argv[])
1857
{
1858
EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
1859
EFI_HANDLE loaderhandle;
1860
EFI_LOADED_IMAGE *loaded_image;
1861
EFI_STATUS status;
1862
struct stat st;
1863
struct devdesc *dev;
1864
char *name, *path;
1865
void *buf;
1866
int fd;
1867
1868
if (argc < 2) {
1869
command_errmsg = "wrong number of arguments";
1870
return (CMD_ERROR);
1871
}
1872
1873
name = argv[1];
1874
1875
if ((fd = open(name, O_RDONLY)) < 0) {
1876
command_errmsg = "no such file";
1877
return (CMD_ERROR);
1878
}
1879
1880
#ifdef LOADER_VERIEXEC
1881
if (verify_file(fd, name, 0, VE_MUST, __func__) < 0) {
1882
sprintf(command_errbuf, "can't verify: %s", name);
1883
close(fd);
1884
return (CMD_ERROR);
1885
}
1886
#endif
1887
1888
if (fstat(fd, &st) < -1) {
1889
command_errmsg = "stat failed";
1890
close(fd);
1891
return (CMD_ERROR);
1892
}
1893
1894
status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
1895
if (status != EFI_SUCCESS) {
1896
command_errmsg = "failed to allocate buffer";
1897
close(fd);
1898
return (CMD_ERROR);
1899
}
1900
if (read(fd, buf, st.st_size) != st.st_size) {
1901
command_errmsg = "error while reading the file";
1902
(void)BS->FreePool(buf);
1903
close(fd);
1904
return (CMD_ERROR);
1905
}
1906
close(fd);
1907
status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
1908
(void)BS->FreePool(buf);
1909
if (status != EFI_SUCCESS) {
1910
command_errmsg = "LoadImage failed";
1911
return (CMD_ERROR);
1912
}
1913
status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
1914
(void **)&loaded_image);
1915
1916
if (argc > 2) {
1917
int i, len = 0;
1918
CHAR16 *argp;
1919
1920
for (i = 2; i < argc; i++)
1921
len += strlen(argv[i]) + 1;
1922
1923
len *= sizeof (*argp);
1924
loaded_image->LoadOptions = argp = malloc (len);
1925
loaded_image->LoadOptionsSize = len;
1926
for (i = 2; i < argc; i++) {
1927
char *ptr = argv[i];
1928
while (*ptr)
1929
*(argp++) = *(ptr++);
1930
*(argp++) = ' ';
1931
}
1932
*(--argv) = 0;
1933
}
1934
1935
if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
1936
#ifdef EFI_ZFS_BOOT
1937
struct zfs_devdesc *z_dev;
1938
#endif
1939
struct disk_devdesc *d_dev;
1940
pdinfo_t *hd, *pd;
1941
1942
switch (dev->d_dev->dv_type) {
1943
#ifdef EFI_ZFS_BOOT
1944
case DEVT_ZFS:
1945
z_dev = (struct zfs_devdesc *)dev;
1946
loaded_image->DeviceHandle =
1947
efizfs_get_handle_by_guid(z_dev->pool_guid);
1948
break;
1949
#endif
1950
case DEVT_NET:
1951
loaded_image->DeviceHandle =
1952
efi_find_handle(dev->d_dev, dev->d_unit);
1953
break;
1954
default:
1955
hd = efiblk_get_pdinfo(dev);
1956
if (STAILQ_EMPTY(&hd->pd_part)) {
1957
loaded_image->DeviceHandle = hd->pd_handle;
1958
break;
1959
}
1960
d_dev = (struct disk_devdesc *)dev;
1961
STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
1962
/*
1963
* d_partition should be 255
1964
*/
1965
if (pd->pd_unit == (uint32_t)d_dev->d_slice) {
1966
loaded_image->DeviceHandle =
1967
pd->pd_handle;
1968
break;
1969
}
1970
}
1971
break;
1972
}
1973
}
1974
1975
dev_cleanup();
1976
status = BS->StartImage(loaderhandle, NULL, NULL);
1977
if (status != EFI_SUCCESS) {
1978
command_errmsg = "StartImage failed";
1979
free(loaded_image->LoadOptions);
1980
loaded_image->LoadOptions = NULL;
1981
status = BS->UnloadImage(loaded_image);
1982
return (CMD_ERROR);
1983
}
1984
1985
return (CMD_ERROR); /* not reached */
1986
}
1987
1988
COMMAND_SET(chain, "chain", "chain load file", command_chain);
1989
1990
#if defined(LOADER_NET_SUPPORT)
1991
extern struct in_addr servip;
1992
static int
1993
command_netserver(int argc, char *argv[])
1994
{
1995
char *proto;
1996
n_long rootaddr;
1997
1998
if (argc > 2) {
1999
command_errmsg = "wrong number of arguments";
2000
return (CMD_ERROR);
2001
}
2002
if (argc < 2) {
2003
proto = netproto == NET_TFTP ? "tftp://" : "nfs://";
2004
printf("Netserver URI: %s%s%s\n", proto, intoa(rootip.s_addr),
2005
rootpath);
2006
return (CMD_OK);
2007
}
2008
if (argc == 2) {
2009
strncpy(rootpath, argv[1], sizeof(rootpath));
2010
rootpath[sizeof(rootpath) -1] = '\0';
2011
if ((rootaddr = net_parse_rootpath()) != INADDR_NONE)
2012
servip.s_addr = rootip.s_addr = rootaddr;
2013
return (CMD_OK);
2014
}
2015
return (CMD_ERROR); /* not reached */
2016
2017
}
2018
2019
COMMAND_SET(netserver, "netserver", "change or display netserver URI",
2020
command_netserver);
2021
#endif
2022
2023