]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/boot/amd64/efi/main.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / boot / amd64 / efi / main.c
1 /*-
2  * Copyright (c) 2008-2010 Rui Paulo
3  * Copyright (c) 2006 Marcel Moolenaar
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <stand.h>
32 #include <string.h>
33 #include <setjmp.h>
34
35 #include <efi.h>
36 #include <efilib.h>
37
38 #include <bootstrap.h>
39 #include <smbios.h>
40 #include "x86_efi.h"
41
42 extern char bootprog_name[];
43 extern char bootprog_rev[];
44 extern char bootprog_date[];
45 extern char bootprog_maker[];
46
47 struct devdesc currdev;         /* our current device */
48 struct arch_switch archsw;      /* MI/MD interface boundary */
49
50 EFI_GUID acpi = ACPI_TABLE_GUID;
51 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
52 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
53 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
54 EFI_GUID mps = MPS_TABLE_GUID;
55 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
56 EFI_GUID smbios = SMBIOS_TABLE_GUID;
57
58 EFI_STATUS
59 main(int argc, CHAR16 *argv[])
60 {
61         char vendor[128];
62         EFI_LOADED_IMAGE *img;
63         EFI_GUID *guid;
64         int i;
65
66         /*
67          * XXX Chicken-and-egg problem; we want to have console output
68          * early, but some console attributes may depend on reading from
69          * eg. the boot device, which we can't do yet.  We can use
70          * printf() etc. once this is done.
71          */
72         cons_probe();
73
74         if (x86_efi_copy_init()) {
75                 printf("failed to allocate staging area\n");
76                 return (EFI_BUFFER_TOO_SMALL);
77         }
78
79         /*
80          * March through the device switch probing for things.
81          */
82         for (i = 0; devsw[i] != NULL; i++)
83                 if (devsw[i]->dv_init != NULL)
84                         (devsw[i]->dv_init)();
85
86         /* Get our loaded image protocol interface structure. */
87         BS->HandleProtocol(IH, &imgid, (VOID**)&img);
88
89         printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
90         printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
91             ST->Hdr.Revision & 0xffff);
92         printf("EFI Firmware: ");
93         /* printf doesn't understand EFI Unicode */
94         ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor);
95         printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16,
96             ST->FirmwareRevision & 0xffff);
97
98         printf("\n");
99         printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
100         printf("(%s, %s)\n", bootprog_maker, bootprog_date);
101
102         efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
103         currdev.d_type = currdev.d_dev->dv_type;
104
105         /*
106          * Disable the watchdog timer. By default the boot manager sets
107          * the timer to 5 minutes before invoking a boot option. If we
108          * want to return to the boot manager, we have to disable the
109          * watchdog timer and since we're an interactive program, we don't
110          * want to wait until the user types "quit". The timer may have
111          * fired by then. We don't care if this fails. It does not prevent
112          * normal functioning in any way...
113          */
114         BS->SetWatchdogTimer(0, 0, 0, NULL);
115
116         env_setenv("currdev", EV_VOLATILE, x86_efi_fmtdev(&currdev),
117             x86_efi_setcurrdev, env_nounset);
118         env_setenv("loaddev", EV_VOLATILE, x86_efi_fmtdev(&currdev), env_noset,
119             env_nounset);
120
121         setenv("LINES", "24", 1);       /* optional */
122
123         archsw.arch_autoload = x86_efi_autoload;
124         archsw.arch_getdev = x86_efi_getdev;
125         archsw.arch_copyin = x86_efi_copyin;
126         archsw.arch_copyout = x86_efi_copyout;
127         archsw.arch_readin = x86_efi_readin;
128
129         for (i = 0; i < ST->NumberOfTableEntries; i++) {
130                 guid = &ST->ConfigurationTable[i].VendorGuid;
131                 if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
132                         smbios_detect(ST->ConfigurationTable[i].VendorTable);
133                         break;
134                 }
135         }
136
137         interact();                     /* doesn't return */
138
139         return (EFI_SUCCESS);           /* keep compiler happy */
140 }
141
142 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
143
144 static int
145 command_reboot(int argc, char *argv[])
146 {
147         int i;
148
149         for (i = 0; devsw[i] != NULL; ++i)
150                 if (devsw[i]->dv_cleanup != NULL)
151                         (devsw[i]->dv_cleanup)();
152
153         RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23,
154             (CHAR16 *)"Reboot from the loader");
155
156         /* NOTREACHED */
157         return (CMD_ERROR);
158 }
159
160 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
161
162 static int
163 command_quit(int argc, char *argv[])
164 {
165         exit(0);
166         return (CMD_OK);
167 }
168
169 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
170
171 static int
172 command_memmap(int argc, char *argv[])
173 {
174         UINTN sz;
175         EFI_MEMORY_DESCRIPTOR *map, *p;
176         UINTN key, dsz;
177         UINT32 dver;
178         EFI_STATUS status;
179         int i, ndesc;
180         static char *types[] = {
181             "Reserved",
182             "LoaderCode",
183             "LoaderData",
184             "BootServicesCode",
185             "BootServicesData",
186             "RuntimeServicesCode",
187             "RuntimeServicesData",
188             "ConventionalMemory",
189             "UnusableMemory",
190             "ACPIReclaimMemory",
191             "ACPIMemoryNVS",
192             "MemoryMappedIO",
193             "MemoryMappedIOPortSpace",
194             "PalCode"
195         };
196
197         sz = 0;
198         status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
199         if (status != EFI_BUFFER_TOO_SMALL) {
200                 printf("Can't determine memory map size\n");
201                 return CMD_ERROR;
202         }
203         map = malloc(sz);
204         status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
205         if (EFI_ERROR(status)) {
206                 printf("Can't read memory map\n");
207                 return CMD_ERROR;
208         }
209
210         ndesc = sz / dsz;
211         printf("%23s %12s %12s %8s %4s\n",
212                "Type", "Physical", "Virtual", "#Pages", "Attr");
213
214         for (i = 0, p = map; i < ndesc;
215              i++, p = NextMemoryDescriptor(p, dsz)) {
216             printf("%23s %012lx %012lx %08lx ",
217                    types[p->Type],
218                    p->PhysicalStart,
219                    p->VirtualStart,
220                    p->NumberOfPages);
221             if (p->Attribute & EFI_MEMORY_UC)
222                 printf("UC ");
223             if (p->Attribute & EFI_MEMORY_WC)
224                 printf("WC ");
225             if (p->Attribute & EFI_MEMORY_WT)
226                 printf("WT ");
227             if (p->Attribute & EFI_MEMORY_WB)
228                 printf("WB ");
229             if (p->Attribute & EFI_MEMORY_UCE)
230                 printf("UCE ");
231             if (p->Attribute & EFI_MEMORY_WP)
232                 printf("WP ");
233             if (p->Attribute & EFI_MEMORY_RP)
234                 printf("RP ");
235             if (p->Attribute & EFI_MEMORY_XP)
236                 printf("XP ");
237             printf("\n");
238         }
239
240         return CMD_OK;
241 }
242
243 COMMAND_SET(configuration, "configuration",
244             "print configuration tables", command_configuration);
245
246 static const char *
247 guid_to_string(EFI_GUID *guid)
248 {
249         static char buf[40];
250
251         sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
252             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
253             guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
254             guid->Data4[5], guid->Data4[6], guid->Data4[7]);
255         return (buf);
256 }
257
258 static int
259 command_configuration(int argc, char *argv[])
260 {
261         int i;
262
263         printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
264         for (i = 0; i < ST->NumberOfTableEntries; i++) {
265                 EFI_GUID *guid;
266
267                 printf("  ");
268                 guid = &ST->ConfigurationTable[i].VendorGuid;
269                 if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
270                         printf("MPS Table");
271                 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
272                         printf("ACPI Table");
273                 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
274                         printf("ACPI 2.0 Table");
275                 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
276                         printf("SMBIOS Table");
277                 else
278                         printf("Unknown Table (%s)", guid_to_string(guid));
279                 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
280         }
281
282         return CMD_OK;
283 }
284
285
286 COMMAND_SET(mode, "mode", "change or display text modes", command_mode);
287
288 static int
289 command_mode(int argc, char *argv[])
290 {
291         UINTN cols, rows;
292         unsigned int mode;
293         int i;
294         char *cp;
295         char rowenv[8];
296         EFI_STATUS status;
297         SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
298
299         conout = ST->ConOut;
300
301         if (argc > 1) {
302                 mode = strtol(argv[1], &cp, 0);
303                 if (cp[0] != '\0') {
304                         printf("Invalid mode\n");
305                         return (CMD_ERROR);
306                 }
307                 status = conout->QueryMode(conout, mode, &cols, &rows);
308                 if (EFI_ERROR(status)) {
309                         printf("invalid mode %d\n", mode);
310                         return (CMD_ERROR);
311                 }
312                 status = conout->SetMode(conout, mode);
313                 if (EFI_ERROR(status)) {
314                         printf("couldn't set mode %d\n", mode);
315                         return (CMD_ERROR);
316                 }
317                 sprintf(rowenv, "%u", (unsigned)rows);
318                 setenv("LINES", rowenv, 1);
319
320                 return (CMD_OK);
321         }
322
323         for (i = 0; ; i++) {
324                 status = conout->QueryMode(conout, i, &cols, &rows);
325                 if (EFI_ERROR(status))
326                         break;
327                 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
328                     (unsigned)rows);
329         }
330
331         if (i != 0)
332                 printf("Choose the mode with \"col <mode number>\"\n"); 
333
334         return (CMD_OK);
335 }
336
337
338 COMMAND_SET(nvram, "nvram", "get or set NVRAM variables", command_nvram);
339
340 static int
341 command_nvram(int argc, char *argv[])
342 {
343         CHAR16 var[128];
344         CHAR16 *data;
345         EFI_STATUS status;
346         EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
347         UINTN varsz, datasz;
348         SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
349         int i;
350
351         conout = ST->ConOut;
352
353         /* Initiate the search */
354         status = RS->GetNextVariableName(&varsz, NULL, NULL);
355
356         for (; status != EFI_NOT_FOUND; ) {
357                 status = RS->GetNextVariableName(&varsz, var,
358                     &varguid);
359                 //if (EFI_ERROR(status))
360                         //break;
361
362                 conout->OutputString(conout, var);
363                 printf("=");
364                 datasz = 0;
365                 status = RS->GetVariable(var, &varguid, NULL, &datasz,
366                     NULL);
367                 /* XXX: check status */
368                 data = malloc(datasz);
369                 status = RS->GetVariable(var, &varguid, NULL, &datasz,
370                     data);
371                 if (EFI_ERROR(status))
372                         printf("<error retrieving variable>");
373                 else {
374                         for (i = 0; i < datasz; i++) {
375                                 if (isalnum(data[i]) || isspace(data[i]))
376                                         printf("%c", data[i]);
377                                 else
378                                         printf("\\x%02x", data[i]);
379                         }
380                 }
381                 /* XXX */
382                 pager_output("\n");
383                 free(data);
384         }
385
386         return (CMD_OK);
387 }