]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/boot/i386/efi/main.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / boot / i386 / 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 "../libi386/libi386.h"
40
41 extern char bootprog_name[];
42 extern char bootprog_rev[];
43 extern char bootprog_date[];
44 extern char bootprog_maker[];
45
46 struct devdesc currdev;         /* our current device */
47 struct arch_switch archsw;      /* MI/MD interface boundary */
48
49 EFI_GUID acpi = ACPI_TABLE_GUID;
50 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
51 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
52 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
53 EFI_GUID mps = MPS_TABLE_GUID;
54 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
55 EFI_GUID smbios = SMBIOS_TABLE_GUID;
56
57 EFI_STATUS
58 main(int argc, CHAR16 *argv[])
59 {
60         char vendor[128];
61         EFI_LOADED_IMAGE *img;
62         int i;
63
64         /* 
65          * XXX Chicken-and-egg problem; we want to have console output
66          * early, but some console attributes may depend on reading from
67          * eg. the boot device, which we can't do yet.  We can use
68          * printf() etc. once this is done.
69          */
70         cons_probe();
71
72         /*
73          * March through the device switch probing for things.
74          */
75         for (i = 0; devsw[i] != NULL; i++)
76                 if (devsw[i]->dv_init != NULL)
77                         (devsw[i]->dv_init)();
78
79         /* Get our loaded image protocol interface structure. */
80         BS->HandleProtocol(IH, &imgid, (VOID**)&img);
81
82         printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
83         printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
84             ST->Hdr.Revision & 0xffff);
85         printf("EFI Firmware: ");
86         /* printf doesn't understand EFI Unicode */
87         ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor);
88         printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16,
89             ST->FirmwareRevision & 0xffff);
90
91         printf("\n");
92         printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
93         printf("(%s, %s)\n", bootprog_maker, bootprog_date);
94
95         efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
96         currdev.d_type = currdev.d_dev->dv_type;
97
98         /*
99          * Disable the watchdog timer. By default the boot manager sets
100          * the timer to 5 minutes before invoking a boot option. If we
101          * want to return to the boot manager, we have to disable the
102          * watchdog timer and since we're an interactive program, we don't
103          * want to wait until the user types "quit". The timer may have
104          * fired by then. We don't care if this fails. It does not prevent
105          * normal functioning in any way...
106          */
107         BS->SetWatchdogTimer(0, 0, 0, NULL);
108
109         env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&currdev),
110             i386_setcurrdev, env_nounset);
111         env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&currdev), env_noset,
112             env_nounset);
113
114         setenv("LINES", "24", 1);       /* optional */
115     
116         archsw.arch_autoload = i386_autoload;
117         archsw.arch_getdev = i386_getdev;
118         archsw.arch_copyin = i386_copyin;
119         archsw.arch_copyout = i386_copyout;
120         archsw.arch_readin = i386_readin;
121
122         interact();                     /* doesn't return */
123
124         return (EFI_SUCCESS);           /* keep compiler happy */
125 }
126
127 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
128
129 static int
130 command_reboot(int argc, char *argv[])
131 {
132         int i;
133
134         for (i = 0; devsw[i] != NULL; ++i)
135                 if (devsw[i]->dv_cleanup != NULL)
136                         (devsw[i]->dv_cleanup)();
137
138         RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23,
139             (CHAR16 *)"Reboot from the loader");
140
141         /* NOTREACHED */
142         return (CMD_ERROR);
143 }
144
145 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
146
147 static int
148 command_quit(int argc, char *argv[])
149 {
150         exit(0);
151         return (CMD_OK);
152 }
153
154 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
155
156 static int
157 command_memmap(int argc, char *argv[])
158 {
159         UINTN sz;
160         EFI_MEMORY_DESCRIPTOR *map, *p;
161         UINTN key, dsz;
162         UINT32 dver;
163         EFI_STATUS status;
164         int i, ndesc;
165         static char *types[] = {
166             "Reserved",
167             "LoaderCode",
168             "LoaderData",
169             "BootServicesCode",
170             "BootServicesData",
171             "RuntimeServicesCode",
172             "RuntimeServicesData",
173             "ConventionalMemory",
174             "UnusableMemory",
175             "ACPIReclaimMemory",
176             "ACPIMemoryNVS",
177             "MemoryMappedIO",
178             "MemoryMappedIOPortSpace",
179             "PalCode"
180         };
181
182         sz = 0;
183         status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
184         if (status != EFI_BUFFER_TOO_SMALL) {
185                 printf("Can't determine memory map size\n");
186                 return CMD_ERROR;
187         }
188         map = malloc(sz);
189         status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
190         if (EFI_ERROR(status)) {
191                 printf("Can't read memory map\n");
192                 return CMD_ERROR;
193         }
194
195         ndesc = sz / dsz;
196         printf("%23s %12s %12s %8s %4s\n",
197                "Type", "Physical", "Virtual", "#Pages", "Attr");
198                
199         for (i = 0, p = map; i < ndesc;
200              i++, p = NextMemoryDescriptor(p, dsz)) {
201             printf("%23s %012lx %012lx %08lx ",
202                    types[p->Type],
203                    p->PhysicalStart,
204                    p->VirtualStart,
205                    p->NumberOfPages);
206             if (p->Attribute & EFI_MEMORY_UC)
207                 printf("UC ");
208             if (p->Attribute & EFI_MEMORY_WC)
209                 printf("WC ");
210             if (p->Attribute & EFI_MEMORY_WT)
211                 printf("WT ");
212             if (p->Attribute & EFI_MEMORY_WB)
213                 printf("WB ");
214             if (p->Attribute & EFI_MEMORY_UCE)
215                 printf("UCE ");
216             if (p->Attribute & EFI_MEMORY_WP)
217                 printf("WP ");
218             if (p->Attribute & EFI_MEMORY_RP)
219                 printf("RP ");
220             if (p->Attribute & EFI_MEMORY_XP)
221                 printf("XP ");
222             printf("\n");
223         }
224
225         return CMD_OK;
226 }
227
228 COMMAND_SET(configuration, "configuration",
229             "print configuration tables", command_configuration);
230
231 static const char *
232 guid_to_string(EFI_GUID *guid)
233 {
234         static char buf[40];
235
236         sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
237             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
238             guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
239             guid->Data4[5], guid->Data4[6], guid->Data4[7]);
240         return (buf);
241 }
242
243 static int
244 command_configuration(int argc, char *argv[])
245 {
246         int i;
247
248         printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
249         for (i = 0; i < ST->NumberOfTableEntries; i++) {
250                 EFI_GUID *guid;
251
252                 printf("  ");
253                 guid = &ST->ConfigurationTable[i].VendorGuid;
254                 if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
255                         printf("MPS Table");
256                 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
257                         printf("ACPI Table");
258                 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
259                         printf("ACPI 2.0 Table");
260                 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
261                         printf("SMBIOS Table");
262                 else
263                         printf("Unknown Table (%s)", guid_to_string(guid));
264                 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
265         }
266
267         return CMD_OK;
268 }    
269
270
271 COMMAND_SET(mode, "mode", "change or display text modes", command_mode);
272
273 static int
274 command_mode(int argc, char *argv[])
275 {
276         unsigned int cols, rows, mode;
277         int i;
278         char *cp;
279         char rowenv[8];
280         EFI_STATUS status;
281         SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
282
283         conout = ST->ConOut;
284
285         if (argc > 1) {
286                 mode = strtol(argv[1], &cp, 0);
287                 if (cp[0] != '\0') {
288                         printf("Invalid mode\n");
289                         return (CMD_ERROR);
290                 }
291                 status = conout->QueryMode(conout, mode, &cols, &rows);
292                 if (EFI_ERROR(status)) {
293                         printf("invalid mode %d\n", mode);
294                         return (CMD_ERROR);
295                 }
296                 status = conout->SetMode(conout, mode);
297                 if (EFI_ERROR(status)) {
298                         printf("couldn't set mode %d\n", mode);
299                         return (CMD_ERROR);
300                 }
301                 sprintf(rowenv, "%d", rows);
302                 setenv("LINES", rowenv, 1);
303
304                 return (CMD_OK);
305         }
306
307         for (i = 0; ; i++) {
308                 status = conout->QueryMode(conout, i, &cols, &rows);
309                 if (EFI_ERROR(status))
310                         break;
311                 printf("Mode %d: %d columns, %d rows\n", i, cols, rows);
312         }
313
314         if (i != 0)
315                 printf("Choose the mode with \"col <mode number>\"\n"); 
316
317         return (CMD_OK);
318 }
319
320
321 COMMAND_SET(nvram, "nvram", "get or set NVRAM variables", command_nvram);
322
323 static int
324 command_nvram(int argc, char *argv[])
325 {
326         CHAR16 var[128];
327         CHAR16 *data;
328         EFI_STATUS status;
329         EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
330         unsigned int varsz;
331         unsigned int datasz;
332         SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
333         int i;
334
335         conout = ST->ConOut;
336
337         /* Initiate the search */
338         status = RS->GetNextVariableName(&varsz, NULL, NULL);
339
340         for (; status != EFI_NOT_FOUND; ) {
341                 status = RS->GetNextVariableName(&varsz, var,
342                     &varguid);
343                 //if (EFI_ERROR(status))
344                         //break;
345
346                 conout->OutputString(conout, var);
347                 printf("=");
348                 datasz = 0;
349                 status = RS->GetVariable(var, &varguid, NULL, &datasz,
350                     NULL);
351                 /* XXX: check status */
352                 data = malloc(datasz);
353                 status = RS->GetVariable(var, &varguid, NULL, &datasz,
354                     data);
355                 if (EFI_ERROR(status))
356                         printf("<error retrieving variable>");
357                 else {
358                         for (i = 0; i < datasz; i++) {
359                                 if (isalnum(data[i]) || isspace(data[i]))
360                                         printf("%c", data[i]);
361                                 else
362                                         printf("\\x%02x", data[i]);
363                         }
364                 }
365                 /* XXX */
366                 pager_output("\n");
367                 free(data);
368         }
369
370         return (CMD_OK);
371 }