1479ab7f0SSascha Wildner /*-
2479ab7f0SSascha Wildner * Copyright (c) 1998 Robert Nordier
3479ab7f0SSascha Wildner * All rights reserved.
4479ab7f0SSascha Wildner * Copyright (c) 2001 Robert Drehmel
5479ab7f0SSascha Wildner * All rights reserved.
6479ab7f0SSascha Wildner * Copyright (c) 2014 Nathan Whitehorn
7479ab7f0SSascha Wildner * All rights reserved.
8479ab7f0SSascha Wildner * Copyright (c) 2015 Eric McCorkle
9479ab7f0SSascha Wildner * All rights reserved.
10479ab7f0SSascha Wildner *
11479ab7f0SSascha Wildner * Redistribution and use in source and binary forms are freely
12479ab7f0SSascha Wildner * permitted provided that the above copyright notice and this
13479ab7f0SSascha Wildner * paragraph and the following disclaimer are duplicated in all
14479ab7f0SSascha Wildner * such forms.
15479ab7f0SSascha Wildner *
16479ab7f0SSascha Wildner * This software is provided "AS IS" and without any express or
17479ab7f0SSascha Wildner * implied warranties, including, without limitation, the implied
18479ab7f0SSascha Wildner * warranties of merchantability and fitness for a particular
19479ab7f0SSascha Wildner * purpose.
20479ab7f0SSascha Wildner *
21479ab7f0SSascha Wildner * $FreeBSD: head/sys/boot/efi/boot1/boot1.c 296713 2016-03-12 06:50:16Z andrew $
22479ab7f0SSascha Wildner */
23479ab7f0SSascha Wildner
24479ab7f0SSascha Wildner #include <sys/param.h>
25479ab7f0SSascha Wildner #include <machine/elf.h>
26479ab7f0SSascha Wildner #include <machine/stdarg.h>
27479ab7f0SSascha Wildner #include <stand.h>
28479ab7f0SSascha Wildner #include <stdarg.h>
29479ab7f0SSascha Wildner
30479ab7f0SSascha Wildner #include <efi.h>
31479ab7f0SSascha Wildner #include <eficonsctl.h>
32479ab7f0SSascha Wildner
33479ab7f0SSascha Wildner #include "boot_module.h"
34479ab7f0SSascha Wildner #include "paths.h"
35479ab7f0SSascha Wildner
36479ab7f0SSascha Wildner #define PATH_CONFIG "/boot/config"
37479ab7f0SSascha Wildner #define PATH_DOTCONFIG "/boot.config"
38479ab7f0SSascha Wildner #define PATH_LOADER "/loader.efi" /* /boot is dedicated */
39479ab7f0SSascha Wildner #define PATH_LOADER_ALT "/boot/loader.efi" /* /boot in root */
40479ab7f0SSascha Wildner
41479ab7f0SSascha Wildner static const boot_module_t *boot_modules[] =
42479ab7f0SSascha Wildner {
43479ab7f0SSascha Wildner #ifdef EFI_UFS_BOOT
44479ab7f0SSascha Wildner &ufs_module
45479ab7f0SSascha Wildner #endif
46479ab7f0SSascha Wildner };
47479ab7f0SSascha Wildner
48479ab7f0SSascha Wildner #define NUM_BOOT_MODULES NELEM(boot_modules)
49479ab7f0SSascha Wildner /* The initial number of handles used to query EFI for partitions. */
50479ab7f0SSascha Wildner #define NUM_HANDLES_INIT 24
51479ab7f0SSascha Wildner
52479ab7f0SSascha Wildner static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
53479ab7f0SSascha Wildner static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
54479ab7f0SSascha Wildner static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
55479ab7f0SSascha Wildner static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
56479ab7f0SSascha Wildner
57479ab7f0SSascha Wildner /*
58479ab7f0SSascha Wildner * XXX DragonFly's libstand doesn't provide a way to override the malloc
59479ab7f0SSascha Wildner * implementation yet.
60479ab7f0SSascha Wildner */
61479ab7f0SSascha Wildner #if 0
62479ab7f0SSascha Wildner
63479ab7f0SSascha Wildner /*
64479ab7f0SSascha Wildner * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
65479ab7f0SSascha Wildner * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
66479ab7f0SSascha Wildner * EFI methods.
67479ab7f0SSascha Wildner */
68479ab7f0SSascha Wildner void *
69479ab7f0SSascha Wildner Malloc(size_t len, const char *file __unused, int line __unused)
70479ab7f0SSascha Wildner {
71479ab7f0SSascha Wildner void *out;
72479ab7f0SSascha Wildner
73479ab7f0SSascha Wildner if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
74479ab7f0SSascha Wildner return (out);
75479ab7f0SSascha Wildner
76479ab7f0SSascha Wildner return (NULL);
77479ab7f0SSascha Wildner }
78479ab7f0SSascha Wildner
79479ab7f0SSascha Wildner void
80479ab7f0SSascha Wildner Free(void *buf, const char *file __unused, int line __unused)
81479ab7f0SSascha Wildner {
82479ab7f0SSascha Wildner (void)BS->FreePool(buf);
83479ab7f0SSascha Wildner }
84479ab7f0SSascha Wildner
85479ab7f0SSascha Wildner #endif
86479ab7f0SSascha Wildner
87479ab7f0SSascha Wildner /*
88479ab7f0SSascha Wildner * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
89479ab7f0SSascha Wildner * FALSE otherwise.
90479ab7f0SSascha Wildner */
91479ab7f0SSascha Wildner static BOOLEAN
nodes_match(EFI_DEVICE_PATH * imgpath,EFI_DEVICE_PATH * devpath)92479ab7f0SSascha Wildner nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
93479ab7f0SSascha Wildner {
94479ab7f0SSascha Wildner size_t len;
95479ab7f0SSascha Wildner
96479ab7f0SSascha Wildner if (imgpath == NULL || imgpath->Type != devpath->Type ||
97479ab7f0SSascha Wildner imgpath->SubType != devpath->SubType)
98479ab7f0SSascha Wildner return (FALSE);
99479ab7f0SSascha Wildner
100479ab7f0SSascha Wildner len = DevicePathNodeLength(imgpath);
101479ab7f0SSascha Wildner if (len != DevicePathNodeLength(devpath))
102479ab7f0SSascha Wildner return (FALSE);
103479ab7f0SSascha Wildner
104479ab7f0SSascha Wildner return (memcmp(imgpath, devpath, (size_t)len) == 0);
105479ab7f0SSascha Wildner }
106479ab7f0SSascha Wildner
107479ab7f0SSascha Wildner /*
108479ab7f0SSascha Wildner * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
109e782c7f6SSascha Wildner * in imgpath and devpath match up to their respect occurrences of a media
110479ab7f0SSascha Wildner * node, FALSE otherwise.
111479ab7f0SSascha Wildner */
112479ab7f0SSascha Wildner static BOOLEAN
device_paths_match(EFI_DEVICE_PATH * imgpath,EFI_DEVICE_PATH * devpath)113479ab7f0SSascha Wildner device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
114479ab7f0SSascha Wildner {
115479ab7f0SSascha Wildner
116479ab7f0SSascha Wildner if (imgpath == NULL)
117479ab7f0SSascha Wildner return (FALSE);
118479ab7f0SSascha Wildner
119479ab7f0SSascha Wildner while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
120479ab7f0SSascha Wildner if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
121479ab7f0SSascha Wildner IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
122479ab7f0SSascha Wildner return (TRUE);
123479ab7f0SSascha Wildner
124479ab7f0SSascha Wildner if (!nodes_match(imgpath, devpath))
125479ab7f0SSascha Wildner return (FALSE);
126479ab7f0SSascha Wildner
127479ab7f0SSascha Wildner imgpath = NextDevicePathNode(imgpath);
128479ab7f0SSascha Wildner devpath = NextDevicePathNode(devpath);
129479ab7f0SSascha Wildner }
130479ab7f0SSascha Wildner
131479ab7f0SSascha Wildner return (FALSE);
132479ab7f0SSascha Wildner }
133479ab7f0SSascha Wildner
134479ab7f0SSascha Wildner /*
135479ab7f0SSascha Wildner * devpath_last returns the last non-path end node in devpath.
136479ab7f0SSascha Wildner */
137479ab7f0SSascha Wildner static EFI_DEVICE_PATH *
devpath_last(EFI_DEVICE_PATH * devpath)138479ab7f0SSascha Wildner devpath_last(EFI_DEVICE_PATH *devpath)
139479ab7f0SSascha Wildner {
140479ab7f0SSascha Wildner
141479ab7f0SSascha Wildner while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
142479ab7f0SSascha Wildner devpath = NextDevicePathNode(devpath);
143479ab7f0SSascha Wildner
144479ab7f0SSascha Wildner return (devpath);
145479ab7f0SSascha Wildner }
146479ab7f0SSascha Wildner
147479ab7f0SSascha Wildner /*
148479ab7f0SSascha Wildner * devpath_node_str is a basic output method for a devpath node which
149479ab7f0SSascha Wildner * only understands a subset of the available sub types.
150479ab7f0SSascha Wildner *
151479ab7f0SSascha Wildner * If we switch to UEFI 2.x then we should update it to use:
152479ab7f0SSascha Wildner * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
153479ab7f0SSascha Wildner */
154479ab7f0SSascha Wildner static int
devpath_node_str(char * buf,size_t size,EFI_DEVICE_PATH * devpath)155479ab7f0SSascha Wildner devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
156479ab7f0SSascha Wildner {
157479ab7f0SSascha Wildner
158479ab7f0SSascha Wildner switch (devpath->Type) {
159479ab7f0SSascha Wildner case MESSAGING_DEVICE_PATH:
160479ab7f0SSascha Wildner switch (devpath->SubType) {
161479ab7f0SSascha Wildner case MSG_ATAPI_DP: {
162479ab7f0SSascha Wildner ATAPI_DEVICE_PATH *atapi;
163479ab7f0SSascha Wildner
164479ab7f0SSascha Wildner atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
165479ab7f0SSascha Wildner return snprintf(buf, size, "ata(%s,%s,0x%x)",
166479ab7f0SSascha Wildner (atapi->PrimarySecondary == 1) ? "Sec" : "Pri",
167479ab7f0SSascha Wildner (atapi->SlaveMaster == 1) ? "Slave" : "Master",
168479ab7f0SSascha Wildner atapi->Lun);
169479ab7f0SSascha Wildner }
170479ab7f0SSascha Wildner case MSG_USB_DP: {
171479ab7f0SSascha Wildner USB_DEVICE_PATH *usb;
172479ab7f0SSascha Wildner
173479ab7f0SSascha Wildner usb = (USB_DEVICE_PATH *)devpath;
174479ab7f0SSascha Wildner return snprintf(buf, size, "usb(0x%02x,0x%02x)",
175479ab7f0SSascha Wildner usb->ParentPortNumber, usb->InterfaceNumber);
176479ab7f0SSascha Wildner }
177479ab7f0SSascha Wildner case MSG_SCSI_DP: {
178479ab7f0SSascha Wildner SCSI_DEVICE_PATH *scsi;
179479ab7f0SSascha Wildner
180479ab7f0SSascha Wildner scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
181479ab7f0SSascha Wildner return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
182479ab7f0SSascha Wildner scsi->Pun, scsi->Lun);
183479ab7f0SSascha Wildner }
184479ab7f0SSascha Wildner case MSG_SATA_DP: {
185479ab7f0SSascha Wildner SATA_DEVICE_PATH *sata;
186479ab7f0SSascha Wildner
187479ab7f0SSascha Wildner sata = (SATA_DEVICE_PATH *)(void *)devpath;
188479ab7f0SSascha Wildner return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
189479ab7f0SSascha Wildner sata->HBAPortNumber, sata->PortMultiplierPortNumber,
190479ab7f0SSascha Wildner sata->Lun);
191479ab7f0SSascha Wildner }
192479ab7f0SSascha Wildner default:
193479ab7f0SSascha Wildner return snprintf(buf, size, "msg(0x%02x)",
194479ab7f0SSascha Wildner devpath->SubType);
195479ab7f0SSascha Wildner }
196479ab7f0SSascha Wildner break;
197479ab7f0SSascha Wildner case HARDWARE_DEVICE_PATH:
198479ab7f0SSascha Wildner switch (devpath->SubType) {
199479ab7f0SSascha Wildner case HW_PCI_DP: {
200479ab7f0SSascha Wildner PCI_DEVICE_PATH *pci;
201479ab7f0SSascha Wildner
202479ab7f0SSascha Wildner pci = (PCI_DEVICE_PATH *)devpath;
203479ab7f0SSascha Wildner return snprintf(buf, size, "pci(0x%02x,0x%02x)",
204479ab7f0SSascha Wildner pci->Device, pci->Function);
205479ab7f0SSascha Wildner }
206479ab7f0SSascha Wildner default:
207479ab7f0SSascha Wildner return snprintf(buf, size, "hw(0x%02x)",
208479ab7f0SSascha Wildner devpath->SubType);
209479ab7f0SSascha Wildner }
210479ab7f0SSascha Wildner break;
211479ab7f0SSascha Wildner case ACPI_DEVICE_PATH: {
212479ab7f0SSascha Wildner ACPI_HID_DEVICE_PATH *acpi;
213479ab7f0SSascha Wildner
214479ab7f0SSascha Wildner acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
215479ab7f0SSascha Wildner if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
216479ab7f0SSascha Wildner switch (EISA_ID_TO_NUM(acpi->HID)) {
217479ab7f0SSascha Wildner case 0x0a03:
218479ab7f0SSascha Wildner return snprintf(buf, size, "pciroot(0x%x)",
219479ab7f0SSascha Wildner acpi->UID);
220479ab7f0SSascha Wildner case 0x0a08:
221479ab7f0SSascha Wildner return snprintf(buf, size, "pcieroot(0x%x)",
222479ab7f0SSascha Wildner acpi->UID);
223479ab7f0SSascha Wildner case 0x0604:
224479ab7f0SSascha Wildner return snprintf(buf, size, "floppy(0x%x)",
225479ab7f0SSascha Wildner acpi->UID);
226479ab7f0SSascha Wildner case 0x0301:
227479ab7f0SSascha Wildner return snprintf(buf, size, "keyboard(0x%x)",
228479ab7f0SSascha Wildner acpi->UID);
229479ab7f0SSascha Wildner case 0x0501:
230479ab7f0SSascha Wildner return snprintf(buf, size, "serial(0x%x)",
231479ab7f0SSascha Wildner acpi->UID);
232479ab7f0SSascha Wildner case 0x0401:
233479ab7f0SSascha Wildner return snprintf(buf, size, "parallelport(0x%x)",
234479ab7f0SSascha Wildner acpi->UID);
235479ab7f0SSascha Wildner default:
236479ab7f0SSascha Wildner return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
237479ab7f0SSascha Wildner EISA_ID_TO_NUM(acpi->HID), acpi->UID);
238479ab7f0SSascha Wildner }
239479ab7f0SSascha Wildner }
240479ab7f0SSascha Wildner
241479ab7f0SSascha Wildner return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
242479ab7f0SSascha Wildner acpi->UID);
243479ab7f0SSascha Wildner }
244479ab7f0SSascha Wildner case MEDIA_DEVICE_PATH:
245479ab7f0SSascha Wildner switch (devpath->SubType) {
246479ab7f0SSascha Wildner case MEDIA_CDROM_DP: {
247479ab7f0SSascha Wildner CDROM_DEVICE_PATH *cdrom;
248479ab7f0SSascha Wildner
249479ab7f0SSascha Wildner cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
250479ab7f0SSascha Wildner return snprintf(buf, size, "cdrom(%x)",
251479ab7f0SSascha Wildner cdrom->BootEntry);
252479ab7f0SSascha Wildner }
253479ab7f0SSascha Wildner case MEDIA_HARDDRIVE_DP: {
254479ab7f0SSascha Wildner HARDDRIVE_DEVICE_PATH *hd;
255479ab7f0SSascha Wildner
256479ab7f0SSascha Wildner hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
257479ab7f0SSascha Wildner return snprintf(buf, size, "hd(%x)",
258479ab7f0SSascha Wildner hd->PartitionNumber);
259479ab7f0SSascha Wildner }
260479ab7f0SSascha Wildner default:
261479ab7f0SSascha Wildner return snprintf(buf, size, "media(0x%02x)",
262479ab7f0SSascha Wildner devpath->SubType);
263479ab7f0SSascha Wildner }
264479ab7f0SSascha Wildner case BBS_DEVICE_PATH:
265479ab7f0SSascha Wildner return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
266479ab7f0SSascha Wildner case END_DEVICE_PATH_TYPE:
267479ab7f0SSascha Wildner return (0);
268479ab7f0SSascha Wildner }
269479ab7f0SSascha Wildner
270479ab7f0SSascha Wildner return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
271479ab7f0SSascha Wildner devpath->SubType);
272479ab7f0SSascha Wildner }
273479ab7f0SSascha Wildner
274479ab7f0SSascha Wildner /*
275479ab7f0SSascha Wildner * devpath_strlcat appends a text description of devpath to buf but not more
276479ab7f0SSascha Wildner * than size - 1 characters followed by NUL-terminator.
277479ab7f0SSascha Wildner */
278479ab7f0SSascha Wildner int
devpath_strlcat(char * buf,size_t size,EFI_DEVICE_PATH * devpath)279479ab7f0SSascha Wildner devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
280479ab7f0SSascha Wildner {
281479ab7f0SSascha Wildner size_t len, used;
282479ab7f0SSascha Wildner const char *sep;
283479ab7f0SSascha Wildner
284479ab7f0SSascha Wildner sep = "";
285479ab7f0SSascha Wildner used = 0;
286479ab7f0SSascha Wildner while (!IsDevicePathEnd(devpath)) {
287479ab7f0SSascha Wildner len = snprintf(buf, size - used, "%s", sep);
288479ab7f0SSascha Wildner used += len;
289479ab7f0SSascha Wildner if (used > size)
290479ab7f0SSascha Wildner return (used);
291479ab7f0SSascha Wildner buf += len;
292479ab7f0SSascha Wildner
293479ab7f0SSascha Wildner len = devpath_node_str(buf, size - used, devpath);
294479ab7f0SSascha Wildner used += len;
295479ab7f0SSascha Wildner if (used > size)
296479ab7f0SSascha Wildner return (used);
297479ab7f0SSascha Wildner buf += len;
298479ab7f0SSascha Wildner devpath = NextDevicePathNode(devpath);
299479ab7f0SSascha Wildner sep = ":";
300479ab7f0SSascha Wildner }
301479ab7f0SSascha Wildner
302479ab7f0SSascha Wildner return (used);
303479ab7f0SSascha Wildner }
304479ab7f0SSascha Wildner
305479ab7f0SSascha Wildner /*
306479ab7f0SSascha Wildner * devpath_str is convenience method which returns the text description of
307479ab7f0SSascha Wildner * devpath using a static buffer, so it isn't thread safe!
308479ab7f0SSascha Wildner */
309479ab7f0SSascha Wildner char *
devpath_str(EFI_DEVICE_PATH * devpath)310479ab7f0SSascha Wildner devpath_str(EFI_DEVICE_PATH *devpath)
311479ab7f0SSascha Wildner {
312479ab7f0SSascha Wildner static char buf[256];
313479ab7f0SSascha Wildner
314479ab7f0SSascha Wildner devpath_strlcat(buf, sizeof(buf), devpath);
315479ab7f0SSascha Wildner
316479ab7f0SSascha Wildner return buf;
317479ab7f0SSascha Wildner }
318479ab7f0SSascha Wildner
319479ab7f0SSascha Wildner /*
320479ab7f0SSascha Wildner * load_loader attempts to load the loader image data.
321479ab7f0SSascha Wildner *
322479ab7f0SSascha Wildner * It tries each module and its respective devices, identified by mod->probe,
323479ab7f0SSascha Wildner * in order until a successful load occurs at which point it returns EFI_SUCCESS
324479ab7f0SSascha Wildner * and EFI_NOT_FOUND otherwise.
325479ab7f0SSascha Wildner *
326479ab7f0SSascha Wildner * Only devices which have preferred matching the preferred parameter are tried.
327479ab7f0SSascha Wildner */
328479ab7f0SSascha Wildner static EFI_STATUS
load_loader(const boot_module_t ** modp,dev_info_t ** devinfop,void ** bufp,size_t * bufsize,BOOLEAN preferred)329479ab7f0SSascha Wildner load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
330479ab7f0SSascha Wildner size_t *bufsize, BOOLEAN preferred)
331479ab7f0SSascha Wildner {
332479ab7f0SSascha Wildner UINTN i;
333479ab7f0SSascha Wildner dev_info_t *dev;
334479ab7f0SSascha Wildner const boot_module_t *mod;
335479ab7f0SSascha Wildner EFI_STATUS status;
336479ab7f0SSascha Wildner
337479ab7f0SSascha Wildner for (i = 0; i < NUM_BOOT_MODULES; i++) {
338479ab7f0SSascha Wildner if (boot_modules[i] == NULL)
339479ab7f0SSascha Wildner continue;
340479ab7f0SSascha Wildner mod = boot_modules[i];
341479ab7f0SSascha Wildner for (dev = mod->devices(); dev != NULL; dev = dev->next) {
342479ab7f0SSascha Wildner if (dev->preferred != preferred)
343479ab7f0SSascha Wildner continue;
344479ab7f0SSascha Wildner
345479ab7f0SSascha Wildner status = mod->load(PATH_LOADER, dev, bufp, bufsize);
346479ab7f0SSascha Wildner if (status == EFI_NOT_FOUND) {
347479ab7f0SSascha Wildner status = mod->load(PATH_LOADER_ALT, dev, bufp,
348479ab7f0SSascha Wildner bufsize);
349479ab7f0SSascha Wildner }
350479ab7f0SSascha Wildner if (status == EFI_SUCCESS) {
351479ab7f0SSascha Wildner *devinfop = dev;
352479ab7f0SSascha Wildner *modp = mod;
353479ab7f0SSascha Wildner return (EFI_SUCCESS);
354479ab7f0SSascha Wildner }
355479ab7f0SSascha Wildner }
356479ab7f0SSascha Wildner }
357479ab7f0SSascha Wildner
358479ab7f0SSascha Wildner return (EFI_NOT_FOUND);
359479ab7f0SSascha Wildner }
360479ab7f0SSascha Wildner
361479ab7f0SSascha Wildner /*
362479ab7f0SSascha Wildner * try_boot only returns if it fails to load the loader. If it succeeds
363479ab7f0SSascha Wildner * it simply boots, otherwise it returns the status of last EFI call.
364479ab7f0SSascha Wildner */
365479ab7f0SSascha Wildner static EFI_STATUS
try_boot(void)366479ab7f0SSascha Wildner try_boot(void)
367479ab7f0SSascha Wildner {
368479ab7f0SSascha Wildner size_t bufsize, loadersize, cmdsize;
369479ab7f0SSascha Wildner char *cmd;
370*3d9fb4d4SMatthew Dillon void *buf;
371*3d9fb4d4SMatthew Dillon void *loaderbuf;
372479ab7f0SSascha Wildner dev_info_t *dev;
373479ab7f0SSascha Wildner const boot_module_t *mod;
374479ab7f0SSascha Wildner EFI_HANDLE loaderhandle;
375479ab7f0SSascha Wildner EFI_LOADED_IMAGE *loaded_image;
376479ab7f0SSascha Wildner EFI_STATUS status;
377479ab7f0SSascha Wildner
378*3d9fb4d4SMatthew Dillon loaderbuf = NULL;
379*3d9fb4d4SMatthew Dillon loadersize = 0;
380*3d9fb4d4SMatthew Dillon
381479ab7f0SSascha Wildner status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
382479ab7f0SSascha Wildner if (status != EFI_SUCCESS) {
383*3d9fb4d4SMatthew Dillon status = load_loader(&mod, &dev, &loaderbuf,
384*3d9fb4d4SMatthew Dillon &loadersize, FALSE);
385479ab7f0SSascha Wildner if (status != EFI_SUCCESS) {
386479ab7f0SSascha Wildner printf("Failed to load '%s' or '%s'\n",
387479ab7f0SSascha Wildner PATH_LOADER, PATH_LOADER_ALT);
388479ab7f0SSascha Wildner return (status);
389479ab7f0SSascha Wildner }
390479ab7f0SSascha Wildner }
391479ab7f0SSascha Wildner
392479ab7f0SSascha Wildner /*
393*3d9fb4d4SMatthew Dillon * Funcions might not initialize response variables on error, make
394*3d9fb4d4SMatthew Dillon * sure we have sanity.
395479ab7f0SSascha Wildner */
396479ab7f0SSascha Wildner cmd = NULL;
397*3d9fb4d4SMatthew Dillon buf = NULL;
398479ab7f0SSascha Wildner cmdsize = 0;
399*3d9fb4d4SMatthew Dillon bufsize = 0;
400*3d9fb4d4SMatthew Dillon
401*3d9fb4d4SMatthew Dillon /*
402*3d9fb4d4SMatthew Dillon * Read in and parse the command line from /boot.config or
403*3d9fb4d4SMatthew Dillon * /boot/config, if present. We'll pass it the next stage via a
404*3d9fb4d4SMatthew Dillon * simple ASCII string. loader.efi has a hack for ASCII strings, so
405*3d9fb4d4SMatthew Dillon * we'll use that to keep the size down here. We only try to read the
406*3d9fb4d4SMatthew Dillon * alternate file if we get EFI_NOT_FOUND because all other errors
407*3d9fb4d4SMatthew Dillon * mean that the boot_module had troubles with the filesystem. We
408*3d9fb4d4SMatthew Dillon * could return early, but we'll let loading the actual kernel sort
409*3d9fb4d4SMatthew Dillon * all that out. Since these files are optional, we don't report
410*3d9fb4d4SMatthew Dillon * errors in trying to read them.
411*3d9fb4d4SMatthew Dillon */
412479ab7f0SSascha Wildner status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
413479ab7f0SSascha Wildner if (status == EFI_NOT_FOUND)
414479ab7f0SSascha Wildner status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
415479ab7f0SSascha Wildner if (status == EFI_SUCCESS) {
416479ab7f0SSascha Wildner cmdsize = bufsize + 1;
417479ab7f0SSascha Wildner cmd = malloc(cmdsize);
418479ab7f0SSascha Wildner if (cmd == NULL)
419479ab7f0SSascha Wildner goto errout;
420479ab7f0SSascha Wildner memcpy(cmd, buf, bufsize);
421479ab7f0SSascha Wildner cmd[bufsize] = '\0';
422479ab7f0SSascha Wildner free(buf);
423479ab7f0SSascha Wildner buf = NULL;
424479ab7f0SSascha Wildner }
425479ab7f0SSascha Wildner
426*3d9fb4d4SMatthew Dillon status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
427*3d9fb4d4SMatthew Dillon loaderbuf, loadersize, &loaderhandle);
428*3d9fb4d4SMatthew Dillon if (status != EFI_SUCCESS) {
429*3d9fb4d4SMatthew Dillon printf("Failed to load image provided by %s, "
430*3d9fb4d4SMatthew Dillon "size: %zu, (0x%llx)\n",
431479ab7f0SSascha Wildner mod->name, loadersize, status);
432479ab7f0SSascha Wildner goto errout;
433479ab7f0SSascha Wildner }
434479ab7f0SSascha Wildner
435*3d9fb4d4SMatthew Dillon status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
436*3d9fb4d4SMatthew Dillon (VOID**)&loaded_image);
437*3d9fb4d4SMatthew Dillon if (status != EFI_SUCCESS) {
438*3d9fb4d4SMatthew Dillon printf("Failed to query LoadedImage provided by %s (0x%llx)\n",
439479ab7f0SSascha Wildner mod->name, status);
440479ab7f0SSascha Wildner goto errout;
441479ab7f0SSascha Wildner }
442479ab7f0SSascha Wildner
443479ab7f0SSascha Wildner if (cmd != NULL)
444479ab7f0SSascha Wildner printf(" command args: %s\n", cmd);
445479ab7f0SSascha Wildner
446479ab7f0SSascha Wildner loaded_image->DeviceHandle = dev->devhandle;
447479ab7f0SSascha Wildner loaded_image->LoadOptionsSize = cmdsize;
448479ab7f0SSascha Wildner loaded_image->LoadOptions = cmd;
449479ab7f0SSascha Wildner
450479ab7f0SSascha Wildner DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
451479ab7f0SSascha Wildner DSTALL(1000000);
452479ab7f0SSascha Wildner DPRINTF(".");
453479ab7f0SSascha Wildner DSTALL(1000000);
454479ab7f0SSascha Wildner DPRINTF(".");
455479ab7f0SSascha Wildner DSTALL(1000000);
456479ab7f0SSascha Wildner DPRINTF(".");
457479ab7f0SSascha Wildner DSTALL(1000000);
458479ab7f0SSascha Wildner DPRINTF(".");
459479ab7f0SSascha Wildner DSTALL(1000000);
460479ab7f0SSascha Wildner DPRINTF(".\n");
461479ab7f0SSascha Wildner
462*3d9fb4d4SMatthew Dillon status = BS->StartImage(loaderhandle, NULL, NULL);
463*3d9fb4d4SMatthew Dillon if (status != EFI_SUCCESS) {
464*3d9fb4d4SMatthew Dillon printf("Failed to start image provided by %s (0x%llx)\n",
465479ab7f0SSascha Wildner mod->name, status);
466479ab7f0SSascha Wildner loaded_image->LoadOptionsSize = 0;
467479ab7f0SSascha Wildner loaded_image->LoadOptions = NULL;
468479ab7f0SSascha Wildner }
469479ab7f0SSascha Wildner
470*3d9fb4d4SMatthew Dillon /*
471*3d9fb4d4SMatthew Dillon * Note that buf and loaderbuf were allocated via boot services,
472*3d9fb4d4SMatthew Dillon * not our local allocator.
473*3d9fb4d4SMatthew Dillon */
474479ab7f0SSascha Wildner errout:
475479ab7f0SSascha Wildner if (cmd != NULL)
476479ab7f0SSascha Wildner free(cmd);
477479ab7f0SSascha Wildner if (buf != NULL)
478*3d9fb4d4SMatthew Dillon (void)BS->FreePool(buf);
479479ab7f0SSascha Wildner if (loaderbuf != NULL)
480*3d9fb4d4SMatthew Dillon (void)BS->FreePool(loaderbuf);
481479ab7f0SSascha Wildner
482479ab7f0SSascha Wildner return (status);
483479ab7f0SSascha Wildner }
484479ab7f0SSascha Wildner
485479ab7f0SSascha Wildner /*
486479ab7f0SSascha Wildner * probe_handle determines if the passed handle represents a logical partition
487479ab7f0SSascha Wildner * if it does it uses each module in order to probe it and if successful it
488479ab7f0SSascha Wildner * returns EFI_SUCCESS.
489479ab7f0SSascha Wildner */
490479ab7f0SSascha Wildner static EFI_STATUS
probe_handle(EFI_HANDLE h,EFI_DEVICE_PATH * imgpath,BOOLEAN * preferred)491479ab7f0SSascha Wildner probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
492479ab7f0SSascha Wildner {
493479ab7f0SSascha Wildner dev_info_t *devinfo;
494479ab7f0SSascha Wildner EFI_BLOCK_IO *blkio;
495479ab7f0SSascha Wildner EFI_DEVICE_PATH *devpath;
496479ab7f0SSascha Wildner EFI_STATUS status;
497479ab7f0SSascha Wildner UINTN i;
498479ab7f0SSascha Wildner
499479ab7f0SSascha Wildner /* Figure out if we're dealing with an actual partition. */
500479ab7f0SSascha Wildner status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
501479ab7f0SSascha Wildner if (status == EFI_UNSUPPORTED)
502479ab7f0SSascha Wildner return (status);
503479ab7f0SSascha Wildner
504479ab7f0SSascha Wildner if (status != EFI_SUCCESS) {
505*3d9fb4d4SMatthew Dillon DPRINTF("\nFailed to query DevicePath (0x%llx)\n",
506479ab7f0SSascha Wildner status);
507479ab7f0SSascha Wildner return (status);
508479ab7f0SSascha Wildner }
509479ab7f0SSascha Wildner
510479ab7f0SSascha Wildner DPRINTF("probing: %s\n", devpath_str(devpath));
511479ab7f0SSascha Wildner
512479ab7f0SSascha Wildner status = OpenProtocolByHandle(h, &BlockIoProtocolGUID,
513479ab7f0SSascha Wildner (void **)&blkio);
514479ab7f0SSascha Wildner if (status == EFI_UNSUPPORTED)
515479ab7f0SSascha Wildner return (status);
516479ab7f0SSascha Wildner
517479ab7f0SSascha Wildner if (status != EFI_SUCCESS) {
518*3d9fb4d4SMatthew Dillon DPRINTF("\nFailed to query BlockIoProtocol (0x%llx)\n",
519479ab7f0SSascha Wildner status);
520479ab7f0SSascha Wildner return (status);
521479ab7f0SSascha Wildner }
522479ab7f0SSascha Wildner
523479ab7f0SSascha Wildner if (!blkio->Media->LogicalPartition)
524479ab7f0SSascha Wildner return (EFI_UNSUPPORTED);
525479ab7f0SSascha Wildner
526479ab7f0SSascha Wildner *preferred = device_paths_match(imgpath, devpath);
527479ab7f0SSascha Wildner
528479ab7f0SSascha Wildner /* Run through each module, see if it can load this partition */
529479ab7f0SSascha Wildner for (i = 0; i < NUM_BOOT_MODULES; i++) {
530479ab7f0SSascha Wildner if (boot_modules[i] == NULL)
531479ab7f0SSascha Wildner continue;
532479ab7f0SSascha Wildner
533*3d9fb4d4SMatthew Dillon status = BS->AllocatePool(EfiLoaderData, sizeof(*devinfo),
534*3d9fb4d4SMatthew Dillon (void **)&devinfo);
535*3d9fb4d4SMatthew Dillon if (status != EFI_SUCCESS) {
536*3d9fb4d4SMatthew Dillon DPRINTF("\nFailed to allocate devinfo (0x%llx)\n",
537479ab7f0SSascha Wildner status);
538479ab7f0SSascha Wildner continue;
539479ab7f0SSascha Wildner }
540479ab7f0SSascha Wildner devinfo->dev = blkio;
541479ab7f0SSascha Wildner devinfo->devpath = devpath;
542479ab7f0SSascha Wildner devinfo->devhandle = h;
543479ab7f0SSascha Wildner devinfo->devdata = NULL;
544479ab7f0SSascha Wildner devinfo->preferred = *preferred;
545479ab7f0SSascha Wildner devinfo->next = NULL;
546479ab7f0SSascha Wildner
547479ab7f0SSascha Wildner status = boot_modules[i]->probe(devinfo);
548479ab7f0SSascha Wildner if (status == EFI_SUCCESS)
549479ab7f0SSascha Wildner return (EFI_SUCCESS);
550479ab7f0SSascha Wildner (void)BS->FreePool(devinfo);
551479ab7f0SSascha Wildner }
552479ab7f0SSascha Wildner
553479ab7f0SSascha Wildner return (EFI_UNSUPPORTED);
554479ab7f0SSascha Wildner }
555479ab7f0SSascha Wildner
556479ab7f0SSascha Wildner /*
557479ab7f0SSascha Wildner * probe_handle_status calls probe_handle and outputs the returned status
558479ab7f0SSascha Wildner * of the call.
559479ab7f0SSascha Wildner */
560479ab7f0SSascha Wildner static void
probe_handle_status(EFI_HANDLE h,EFI_DEVICE_PATH * imgpath)561479ab7f0SSascha Wildner probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
562479ab7f0SSascha Wildner {
563479ab7f0SSascha Wildner EFI_STATUS status;
564479ab7f0SSascha Wildner BOOLEAN preferred;
565479ab7f0SSascha Wildner
566479ab7f0SSascha Wildner preferred = FALSE;
567479ab7f0SSascha Wildner status = probe_handle(h, imgpath, &preferred);
568479ab7f0SSascha Wildner
569479ab7f0SSascha Wildner DPRINTF("probe: ");
570479ab7f0SSascha Wildner switch (status) {
571479ab7f0SSascha Wildner case EFI_UNSUPPORTED:
572479ab7f0SSascha Wildner printf(".");
573479ab7f0SSascha Wildner DPRINTF(" not supported\n");
574479ab7f0SSascha Wildner break;
575479ab7f0SSascha Wildner case EFI_SUCCESS:
576479ab7f0SSascha Wildner if (preferred) {
577479ab7f0SSascha Wildner printf("%c", '*');
578479ab7f0SSascha Wildner DPRINTF(" supported (preferred)\n");
579479ab7f0SSascha Wildner } else {
580479ab7f0SSascha Wildner printf("%c", '+');
581479ab7f0SSascha Wildner DPRINTF(" supported\n");
582479ab7f0SSascha Wildner }
583479ab7f0SSascha Wildner break;
584479ab7f0SSascha Wildner default:
585479ab7f0SSascha Wildner printf("x");
586*3d9fb4d4SMatthew Dillon DPRINTF(" error (0x%llx)\n", status);
587479ab7f0SSascha Wildner break;
588479ab7f0SSascha Wildner }
589479ab7f0SSascha Wildner DSTALL(500000);
590479ab7f0SSascha Wildner }
591479ab7f0SSascha Wildner
592479ab7f0SSascha Wildner EFI_STATUS
efi_main(EFI_HANDLE Ximage,EFI_SYSTEM_TABLE * Xsystab)593479ab7f0SSascha Wildner efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
594479ab7f0SSascha Wildner {
595479ab7f0SSascha Wildner EFI_HANDLE *handles;
596479ab7f0SSascha Wildner EFI_LOADED_IMAGE *img;
597479ab7f0SSascha Wildner EFI_DEVICE_PATH *imgpath;
598479ab7f0SSascha Wildner EFI_STATUS status;
599479ab7f0SSascha Wildner EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
600479ab7f0SSascha Wildner SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
601479ab7f0SSascha Wildner UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
602479ab7f0SSascha Wildner
603479ab7f0SSascha Wildner /* Basic initialization*/
604479ab7f0SSascha Wildner ST = Xsystab;
605479ab7f0SSascha Wildner IH = Ximage;
606479ab7f0SSascha Wildner BS = ST->BootServices;
607479ab7f0SSascha Wildner RS = ST->RuntimeServices;
608479ab7f0SSascha Wildner
609479ab7f0SSascha Wildner /* Set up the console, so printf works. */
610479ab7f0SSascha Wildner status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
611479ab7f0SSascha Wildner (VOID **)&ConsoleControl);
612479ab7f0SSascha Wildner if (status == EFI_SUCCESS)
613479ab7f0SSascha Wildner (void)ConsoleControl->SetMode(ConsoleControl,
614479ab7f0SSascha Wildner EfiConsoleControlScreenText);
615479ab7f0SSascha Wildner /*
616479ab7f0SSascha Wildner * Reset the console and find the best text mode.
617479ab7f0SSascha Wildner */
618479ab7f0SSascha Wildner conout = ST->ConOut;
619479ab7f0SSascha Wildner conout->Reset(conout, TRUE);
620479ab7f0SSascha Wildner max_dim = best_mode = 0;
621479ab7f0SSascha Wildner for (i = 0; ; i++) {
622479ab7f0SSascha Wildner status = conout->QueryMode(conout, i, &cols, &rows);
623479ab7f0SSascha Wildner if (EFI_ERROR(status)) {
624479ab7f0SSascha Wildner /* Mode 1 (80x50) can be unsupported on some hw. */
625479ab7f0SSascha Wildner if (i == 1)
626479ab7f0SSascha Wildner continue;
627479ab7f0SSascha Wildner else
628479ab7f0SSascha Wildner break;
629479ab7f0SSascha Wildner }
630479ab7f0SSascha Wildner if (cols * rows > max_dim) {
631479ab7f0SSascha Wildner max_dim = cols * rows;
632479ab7f0SSascha Wildner best_mode = i;
633479ab7f0SSascha Wildner }
634479ab7f0SSascha Wildner }
635479ab7f0SSascha Wildner if (max_dim > 0)
636479ab7f0SSascha Wildner conout->SetMode(conout, best_mode);
637479ab7f0SSascha Wildner conout->EnableCursor(conout, TRUE);
638479ab7f0SSascha Wildner conout->ClearScreen(conout);
639479ab7f0SSascha Wildner
640479ab7f0SSascha Wildner printf("\n>> DragonFly EFI boot block\n");
641479ab7f0SSascha Wildner printf(" Loader path: %s:%s\n\n", PATH_LOADER, PATH_LOADER_ALT);
642479ab7f0SSascha Wildner printf(" Initializing modules:");
643479ab7f0SSascha Wildner for (i = 0; i < NUM_BOOT_MODULES; i++) {
644479ab7f0SSascha Wildner if (boot_modules[i] == NULL)
645479ab7f0SSascha Wildner continue;
646479ab7f0SSascha Wildner
647479ab7f0SSascha Wildner printf(" %s", boot_modules[i]->name);
648479ab7f0SSascha Wildner if (boot_modules[i]->init != NULL)
649479ab7f0SSascha Wildner boot_modules[i]->init();
650479ab7f0SSascha Wildner }
651479ab7f0SSascha Wildner putchar('\n');
652479ab7f0SSascha Wildner
653479ab7f0SSascha Wildner /* Get all the device handles */
654479ab7f0SSascha Wildner hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
655479ab7f0SSascha Wildner if ((status = BS->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
656479ab7f0SSascha Wildner != EFI_SUCCESS)
657*3d9fb4d4SMatthew Dillon panic("Failed to allocate %d handles (0x%llx)", NUM_HANDLES_INIT,
658479ab7f0SSascha Wildner status);
659479ab7f0SSascha Wildner
660479ab7f0SSascha Wildner status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
661479ab7f0SSascha Wildner &hsize, handles);
662479ab7f0SSascha Wildner switch (status) {
663479ab7f0SSascha Wildner case EFI_SUCCESS:
664479ab7f0SSascha Wildner break;
665479ab7f0SSascha Wildner case EFI_BUFFER_TOO_SMALL:
666479ab7f0SSascha Wildner (void)BS->FreePool(handles);
667479ab7f0SSascha Wildner if ((status = BS->AllocatePool(EfiLoaderData, hsize,
668479ab7f0SSascha Wildner (void **)&handles)) != EFI_SUCCESS) {
669*3d9fb4d4SMatthew Dillon panic("Failed to allocate %llu handles (0x%llx)", hsize /
670479ab7f0SSascha Wildner sizeof(*handles), status);
671479ab7f0SSascha Wildner }
672479ab7f0SSascha Wildner status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
673479ab7f0SSascha Wildner NULL, &hsize, handles);
674479ab7f0SSascha Wildner if (status != EFI_SUCCESS)
675*3d9fb4d4SMatthew Dillon panic("Failed to get device handles (0x%llx)\n",
676479ab7f0SSascha Wildner status);
677479ab7f0SSascha Wildner break;
678479ab7f0SSascha Wildner default:
679*3d9fb4d4SMatthew Dillon panic("Failed to get device handles (0x%llx)",
680479ab7f0SSascha Wildner status);
681479ab7f0SSascha Wildner }
682479ab7f0SSascha Wildner
683479ab7f0SSascha Wildner /* Scan all partitions, probing with all modules. */
684479ab7f0SSascha Wildner nhandles = hsize / sizeof(*handles);
685479ab7f0SSascha Wildner printf(" Probing %llu block devices...", nhandles);
686479ab7f0SSascha Wildner DPRINTF("\n");
687479ab7f0SSascha Wildner
688479ab7f0SSascha Wildner /* Determine the devpath of our image so we can prefer it. */
689479ab7f0SSascha Wildner status = OpenProtocolByHandle(IH, &LoadedImageGUID, (VOID**)&img);
690479ab7f0SSascha Wildner imgpath = NULL;
691479ab7f0SSascha Wildner if (status == EFI_SUCCESS) {
692479ab7f0SSascha Wildner status = OpenProtocolByHandle(img->DeviceHandle,
693*3d9fb4d4SMatthew Dillon &DevicePathGUID,
694*3d9fb4d4SMatthew Dillon (void **)&imgpath);
695*3d9fb4d4SMatthew Dillon if (status != EFI_SUCCESS) {
696*3d9fb4d4SMatthew Dillon DPRINTF("Failed to get image DevicePath (0x%llx)\n",
697479ab7f0SSascha Wildner status);
698*3d9fb4d4SMatthew Dillon }
699479ab7f0SSascha Wildner DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
700479ab7f0SSascha Wildner }
701479ab7f0SSascha Wildner
702479ab7f0SSascha Wildner for (i = 0; i < nhandles; i++)
703479ab7f0SSascha Wildner probe_handle_status(handles[i], imgpath);
704479ab7f0SSascha Wildner printf(" done\n");
705479ab7f0SSascha Wildner
706479ab7f0SSascha Wildner /* Status summary. */
707479ab7f0SSascha Wildner for (i = 0; i < NUM_BOOT_MODULES; i++) {
708479ab7f0SSascha Wildner if (boot_modules[i] != NULL) {
709479ab7f0SSascha Wildner printf(" ");
710479ab7f0SSascha Wildner boot_modules[i]->status();
711479ab7f0SSascha Wildner }
712479ab7f0SSascha Wildner }
713479ab7f0SSascha Wildner
714479ab7f0SSascha Wildner try_boot();
715479ab7f0SSascha Wildner
716479ab7f0SSascha Wildner /* If we get here, we're out of luck... */
717479ab7f0SSascha Wildner panic("No bootable partitions found!");
718479ab7f0SSascha Wildner }
719479ab7f0SSascha Wildner
720479ab7f0SSascha Wildner /*
721479ab7f0SSascha Wildner * add_device adds a device to the passed devinfo list.
722479ab7f0SSascha Wildner */
723479ab7f0SSascha Wildner void
add_device(dev_info_t ** devinfop,dev_info_t * devinfo)724479ab7f0SSascha Wildner add_device(dev_info_t **devinfop, dev_info_t *devinfo)
725479ab7f0SSascha Wildner {
726479ab7f0SSascha Wildner dev_info_t *dev;
727479ab7f0SSascha Wildner
728479ab7f0SSascha Wildner if (*devinfop == NULL) {
729479ab7f0SSascha Wildner *devinfop = devinfo;
730479ab7f0SSascha Wildner return;
731479ab7f0SSascha Wildner }
732479ab7f0SSascha Wildner
733479ab7f0SSascha Wildner for (dev = *devinfop; dev->next != NULL; dev = dev->next)
734479ab7f0SSascha Wildner ;
735479ab7f0SSascha Wildner
736479ab7f0SSascha Wildner dev->next = devinfo;
737479ab7f0SSascha Wildner }
738479ab7f0SSascha Wildner
739479ab7f0SSascha Wildner void
panic(const char * fmt,...)740479ab7f0SSascha Wildner panic(const char *fmt, ...)
741479ab7f0SSascha Wildner {
742479ab7f0SSascha Wildner va_list ap;
743479ab7f0SSascha Wildner
744479ab7f0SSascha Wildner printf("panic: ");
745479ab7f0SSascha Wildner va_start(ap, fmt);
746479ab7f0SSascha Wildner vprintf(fmt, ap);
747479ab7f0SSascha Wildner va_end(ap);
748479ab7f0SSascha Wildner printf("\n");
749479ab7f0SSascha Wildner
750479ab7f0SSascha Wildner while (1) {}
751479ab7f0SSascha Wildner }
752479ab7f0SSascha Wildner
753479ab7f0SSascha Wildner void
putchar(int c)754479ab7f0SSascha Wildner putchar(int c)
755479ab7f0SSascha Wildner {
756479ab7f0SSascha Wildner CHAR16 buf[2];
757479ab7f0SSascha Wildner
758479ab7f0SSascha Wildner if (c == '\n') {
759479ab7f0SSascha Wildner buf[0] = '\r';
760479ab7f0SSascha Wildner buf[1] = 0;
761479ab7f0SSascha Wildner ST->ConOut->OutputString(ST->ConOut, buf);
762479ab7f0SSascha Wildner }
763479ab7f0SSascha Wildner buf[0] = c;
764479ab7f0SSascha Wildner buf[1] = 0;
765479ab7f0SSascha Wildner ST->ConOut->OutputString(ST->ConOut, buf);
766479ab7f0SSascha Wildner }
767