kernel: Use NULL for pointers.
[dragonfly.git] / sys / boot / efi / loader / main.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
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  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/boot/efi/loader/main.c,v 1.20 2003/08/02 08:22:03 marcel Exp $
28  */
29
30 #include <stand.h>
31 #include <string.h>
32 #include <setjmp.h>
33 #include <machine/sal.h>
34 #include <machine/pal.h>
35 #include <machine/pte.h>
36 #include <machine/dig64.h>
37
38 #include <efi.h>
39 #include <efilib.h>
40
41 #include "bootstrap.h"
42 #include "efiboot.h"
43
44 extern char bootprog_name[];
45 extern char bootprog_rev[];
46 extern char bootprog_date[];
47 extern char bootprog_maker[];
48
49 struct efi_devdesc      currdev;        /* our current device */
50 struct arch_switch      archsw;         /* MI/MD interface boundary */
51
52 extern u_int64_t        ia64_pal_entry;
53
54 EFI_GUID acpi = ACPI_TABLE_GUID;
55 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
56 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
57 EFI_GUID hcdp = HCDP_TABLE_GUID;
58 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
59 EFI_GUID mps = MPS_TABLE_GUID;
60 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
61 EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
62 EFI_GUID smbios = SMBIOS_TABLE_GUID;
63
64 static void
65 find_pal_proc(void)
66 {
67         int i;
68         struct sal_system_table *saltab = NULL;
69         static int sizes[6] = {
70                 48, 32, 16, 32, 16, 16
71         };
72         u_int8_t *p;
73
74         saltab = efi_get_table(&sal);
75         if (saltab == NULL) {
76                 printf("Can't find SAL System Table\n");
77                 return;
78         }
79
80         if (memcmp(saltab->sal_signature, "SST_", 4)) {
81                 printf("Bad signature for SAL System Table\n");
82                 return;
83         }
84
85         p = (u_int8_t *) (saltab + 1);
86         for (i = 0; i < saltab->sal_entry_count; i++) {
87                 if (*p == 0) {
88                         struct sal_entrypoint_descriptor *dp;
89                         dp = (struct sal_entrypoint_descriptor *) p;
90                         ia64_pal_entry = dp->sale_pal_proc;
91                         return;
92                 }
93                 p += sizes[*p];
94         }
95
96         printf("Can't find PAL proc\n");
97         return;
98 }
99
100 EFI_STATUS
101 main(int argc, CHAR16 *argv[])
102 {
103         EFI_LOADED_IMAGE *img;
104         int i;
105
106         /* 
107          * XXX Chicken-and-egg problem; we want to have console output
108          * early, but some console attributes may depend on reading from
109          * eg. the boot device, which we can't do yet.  We can use
110          * printf() etc. once this is done.
111          */
112         cons_probe();
113
114         /*
115          * Initialise the block cache
116          */
117         bcache_init(32, 512);           /* 16k XXX tune this */
118
119         find_pal_proc();
120
121         /*
122          * March through the device switch probing for things.
123          */
124         for (i = 0; devsw[i] != NULL; i++)
125                 if (devsw[i]->dv_init != NULL)
126                         (devsw[i]->dv_init)();
127
128         efinet_init_driver();
129
130         /* Get our loaded image protocol interface structure. */
131         BS->HandleProtocol(IH, &imgid, (VOID**)&img);
132
133         printf("Image base: 0x%016lx\n", (u_long)img->ImageBase);
134
135         printf("\n");
136         printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
137         printf("(%s, %s)\n", bootprog_maker, bootprog_date);
138
139         i = efifs_get_unit(img->DeviceHandle);
140         if (i >= 0) {
141                 currdev.d_dev = devsw[0];               /* XXX disk */
142                 currdev.d_kind.efidisk.unit = i;
143                 /* XXX should be able to detect this, default to autoprobe */
144                 currdev.d_kind.efidisk.slice = -1;
145                 currdev.d_kind.efidisk.partition = 0;
146         } else {
147                 currdev.d_dev = devsw[1];               /* XXX net */
148                 currdev.d_kind.netif.unit = 0;          /* XXX */
149         }
150         currdev.d_type = currdev.d_dev->dv_type;
151
152         /*
153          * Disable the watchdog timer. By default the boot manager sets
154          * the timer to 5 minutes before invoking a boot option. If we
155          * want to return to the boot manager, we have to disable the
156          * watchdog timer and since we're an interactive program, we don't
157          * want to wait until the user types "quit". The timer may have
158          * fired by then. We don't care if this fails. It does not prevent
159          * normal functioning in any way...
160          */
161         BS->SetWatchdogTimer(0, 0, 0, NULL);
162
163         env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
164             efi_setcurrdev, env_nounset);
165         env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
166             env_nounset);
167
168         setenv("LINES", "24", 1);       /* optional */
169     
170         archsw.arch_autoload = efi_autoload;
171         archsw.arch_getdev = efi_getdev;
172         archsw.arch_copyin = efi_copyin;
173         archsw.arch_copyout = efi_copyout;
174         archsw.arch_readin = efi_readin;
175
176         interact();                     /* doesn't return */
177
178         return (EFI_SUCCESS);           /* keep compiler happy */
179 }
180
181 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
182
183 static int
184 command_quit(int argc, char *argv[])
185 {
186         exit(0);
187         return (CMD_OK);
188 }
189
190 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
191
192 static int
193 command_memmap(int argc, char *argv[])
194 {
195         UINTN sz;
196         EFI_MEMORY_DESCRIPTOR *map, *p;
197         UINTN key, dsz;
198         UINT32 dver;
199         EFI_STATUS status;
200         int i, ndesc;
201         static char *types[] = {
202             "Reserved",
203             "LoaderCode",
204             "LoaderData",
205             "BootServicesCode",
206             "BootServicesData",
207             "RuntimeServicesCode",
208             "RuntimeServicesData",
209             "ConventionalMemory",
210             "UnusableMemory",
211             "ACPIReclaimMemory",
212             "ACPIMemoryNVS",
213             "MemoryMappedIO",
214             "MemoryMappedIOPortSpace",
215             "PalCode"
216         };
217
218         sz = 0;
219         status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
220         if (status != EFI_BUFFER_TOO_SMALL) {
221                 printf("Can't determine memory map size\n");
222                 return CMD_ERROR;
223         }
224         map = malloc(sz);
225         status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
226         if (EFI_ERROR(status)) {
227                 printf("Can't read memory map\n");
228                 return CMD_ERROR;
229         }
230
231         ndesc = sz / dsz;
232         printf("%23s %12s %12s %8s %4s\n",
233                "Type", "Physical", "Virtual", "#Pages", "Attr");
234                
235         for (i = 0, p = map; i < ndesc;
236              i++, p = NextMemoryDescriptor(p, dsz)) {
237             printf("%23s %012lx %012lx %08lx ",
238                    types[p->Type],
239                    p->PhysicalStart,
240                    p->VirtualStart,
241                    p->NumberOfPages);
242             if (p->Attribute & EFI_MEMORY_UC)
243                 printf("UC ");
244             if (p->Attribute & EFI_MEMORY_WC)
245                 printf("WC ");
246             if (p->Attribute & EFI_MEMORY_WT)
247                 printf("WT ");
248             if (p->Attribute & EFI_MEMORY_WB)
249                 printf("WB ");
250             if (p->Attribute & EFI_MEMORY_UCE)
251                 printf("UCE ");
252             if (p->Attribute & EFI_MEMORY_WP)
253                 printf("WP ");
254             if (p->Attribute & EFI_MEMORY_RP)
255                 printf("RP ");
256             if (p->Attribute & EFI_MEMORY_XP)
257                 printf("XP ");
258             if (p->Attribute & EFI_MEMORY_RUNTIME)
259                 printf("RUNTIME");
260             printf("\n");
261         }
262
263         return CMD_OK;
264 }
265
266 COMMAND_SET(configuration, "configuration",
267             "print configuration tables", command_configuration);
268
269 static const char *
270 guid_to_string(EFI_GUID *guid)
271 {
272         static char buf[40];
273
274         sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
275             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
276             guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
277             guid->Data4[5], guid->Data4[6], guid->Data4[7]);
278         return (buf);
279 }
280
281 static int
282 command_configuration(int argc, char *argv[])
283 {
284         int i;
285
286         printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
287         for (i = 0; i < ST->NumberOfTableEntries; i++) {
288                 EFI_GUID *guid;
289
290                 printf("  ");
291                 guid = &ST->ConfigurationTable[i].VendorGuid;
292                 if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
293                         printf("MPS Table");
294                 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
295                         printf("ACPI Table");
296                 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
297                         printf("ACPI 2.0 Table");
298                 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
299                         printf("SMBIOS Table");
300                 else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
301                         printf("SAL System Table");
302                 else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
303                         printf("DIG64 HCDP Table");
304                 else
305                         printf("Unknown Table (%s)", guid_to_string(guid));
306                 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
307         }
308
309         return CMD_OK;
310 }    
311
312 COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
313
314 static int
315 command_sal(int argc, char *argv[])
316 {
317         int i;
318         struct sal_system_table *saltab = NULL;
319         static int sizes[6] = {
320                 48, 32, 16, 32, 16, 16
321         };
322         u_int8_t *p;
323
324         saltab = efi_get_table(&sal);
325         if (saltab == NULL) {
326                 printf("Can't find SAL System Table\n");
327                 return CMD_ERROR;
328         }
329
330         if (memcmp(saltab->sal_signature, "SST_", 4)) {
331                 printf("Bad signature for SAL System Table\n");
332                 return CMD_ERROR;
333         }
334
335         printf("SAL Revision %x.%02x\n",
336                saltab->sal_rev[1],
337                saltab->sal_rev[0]);
338         printf("SAL A Version %x.%02x\n",
339                saltab->sal_a_version[1],
340                saltab->sal_a_version[0]);
341         printf("SAL B Version %x.%02x\n",
342                saltab->sal_b_version[1],
343                saltab->sal_b_version[0]);
344
345         p = (u_int8_t *) (saltab + 1);
346         for (i = 0; i < saltab->sal_entry_count; i++) {
347                 printf("  Desc %d", *p);
348                 if (*p == 0) {
349                         struct sal_entrypoint_descriptor *dp;
350                         dp = (struct sal_entrypoint_descriptor *) p;
351                         printf("\n");
352                         printf("    PAL Proc at 0x%lx\n",
353                                dp->sale_pal_proc);
354                         printf("    SAL Proc at 0x%lx\n",
355                                dp->sale_sal_proc);
356                         printf("    SAL GP at 0x%lx\n",
357                                dp->sale_sal_gp);
358                 } else if (*p == 1) {
359                         struct sal_memory_descriptor *dp;
360                         dp = (struct sal_memory_descriptor *) p;
361                         printf(" Type %d.%d, ",
362                                dp->sale_memory_type[0],
363                                dp->sale_memory_type[1]);
364                         printf("Address 0x%lx, ",
365                                dp->sale_physical_address);
366                         printf("Length 0x%x\n",
367                                dp->sale_length);
368                 } else if (*p == 5) {
369                         struct sal_ap_wakeup_descriptor *dp;
370                         dp = (struct sal_ap_wakeup_descriptor *) p;
371                         printf("\n");
372                         printf("    Mechanism %d\n", dp->sale_mechanism);
373                         printf("    Vector 0x%lx\n", dp->sale_vector);
374                 } else
375                         printf("\n");
376
377                 p += sizes[*p];
378         }
379
380         return CMD_OK;
381 }
382
383 int
384 print_trs(int type)
385 {
386         struct ia64_pal_result  res;
387         int                     i, maxtr;
388         struct {
389                 struct ia64_pte pte;
390                 struct ia64_itir itir;
391                 struct ia64_ifa ifa;
392                 struct ia64_rr  rr;
393         }                       buf;
394         static const char*      psnames[] = {
395                 "1B",   "2B",   "4B",   "8B",
396                 "16B",  "32B",  "64B",  "128B",
397                 "256B", "512B", "1K",   "2K",
398                 "4K",   "8K",   "16K",  "32K",
399                 "64K",  "128K", "256K", "512K",
400                 "1M",   "2M",   "4M",   "8M",
401                 "16M",  "32M",  "64M",  "128M",
402                 "256M", "512M", "1G",   "2G"
403         };
404         static const char*      manames[] = {
405                 "WB",   "bad",  "bad",  "bad",
406                 "UC",   "UCE",  "WC",   "NaT",
407                 
408         };
409
410         res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
411         if (res.pal_status != 0) {
412                 printf("Can't get VM summary\n");
413                 return CMD_ERROR;
414         }
415
416         if (type == 0)
417                 maxtr = (res.pal_result[0] >> 40) & 0xff;
418         else
419                 maxtr = (res.pal_result[0] >> 32) & 0xff;
420
421         printf("%d translation registers\n", maxtr);
422
423         pager_open();
424         pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
425         for (i = 0; i <= maxtr; i++) {
426                 char lbuf[128];
427
428                 bzero(&buf, sizeof(buf));
429                 res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
430                                             (u_int64_t) &buf);
431                 if (res.pal_status != 0)
432                         break;
433
434                 /* Only display valid translations */
435                 if ((buf.ifa.ifa_ig & 1) == 0)
436                         continue;
437
438                 if (!(res.pal_result[0] & 1))
439                         buf.pte.pte_ar = 0;
440                 if (!(res.pal_result[0] & 2))
441                         buf.pte.pte_pl = 0;
442                 if (!(res.pal_result[0] & 4))
443                         buf.pte.pte_d = 0;
444                 if (!(res.pal_result[0] & 8))
445                         buf.pte.pte_ma = 0;
446                 sprintf(lbuf,
447         "%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d %-3s %d %06x\n",
448                         i,
449                         buf.rr.rr_rid,
450                         buf.ifa.ifa_vpn,
451                         buf.pte.pte_ppn,
452                         psnames[buf.itir.itir_ps],
453                         buf.pte.pte_ed,
454                         buf.pte.pte_ar,
455                         buf.pte.pte_pl,
456                         buf.pte.pte_d,
457                         buf.pte.pte_a,
458                         manames[buf.pte.pte_ma],
459                         buf.pte.pte_p,
460                         buf.itir.itir_key);
461                 pager_output(lbuf);
462         }
463         pager_close();
464
465         if (res.pal_status != 0) {
466                 printf("Error while getting TR contents\n");
467                 return CMD_ERROR;
468         }
469         return CMD_OK;
470 }
471
472 COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
473
474 static int
475 command_itr(int argc, char *argv[])
476 {
477         return print_trs(0);
478 }
479
480 COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
481
482 static int
483 command_dtr(int argc, char *argv[])
484 {
485         return print_trs(1);
486 }
487
488 COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
489
490 static char *
491 hcdp_string(char *s, u_int len)
492 {
493         static char buffer[256];
494
495         memcpy(buffer, s, len);
496         buffer[len] = 0;
497         return (buffer);
498 }
499         
500 static int
501 command_hcdp(int argc, char *argv[])
502 {
503         struct dig64_hcdp_table *tbl;
504         struct dig64_hcdp_entry *ent;
505         struct dig64_gas *gas;
506         int i;
507
508         tbl = efi_get_table(&hcdp);
509         if (tbl == NULL) {
510                 printf("No HCDP table present\n");
511                 return (CMD_OK);
512         }
513         if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
514                 printf("HCDP table has invalid signature\n");
515                 return (CMD_OK);
516         }
517         if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) {
518                 printf("HCDP table too short\n");
519                 return (CMD_OK);
520         }
521         printf("HCDP table at 0x%016lx\n", (u_long)tbl);
522         printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
523         printf("Length     = %u\n", tbl->length);
524         printf("Revision   = %u\n", tbl->revision);
525         printf("Checksum   = %u\n", tbl->checksum);
526         printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
527         printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
528         printf("OEM rev    = %u\n", tbl->oem_rev);
529         printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
530         printf("Creator rev= %u\n", tbl->creator_rev);
531         printf("Entries    = %u\n", tbl->entries);
532         for (i = 0; i < tbl->entries; i++) {
533                 ent = tbl->entry + i;
534                 printf("Entry #%d:\n", i + 1);
535                 printf("    Type      = %u\n", ent->type);
536                 printf("    Databits  = %u\n", ent->databits);
537                 printf("    Parity    = %u\n", ent->parity);
538                 printf("    Stopbits  = %u\n", ent->stopbits);
539                 printf("    PCI seg   = %u\n", ent->pci_segment);
540                 printf("    PCI bus   = %u\n", ent->pci_bus);
541                 printf("    PCI dev   = %u\n", ent->pci_device);
542                 printf("    PCI func  = %u\n", ent->pci_function);
543                 printf("    Interrupt = %u\n", ent->interrupt);
544                 printf("    PCI flag  = %u\n", ent->pci_flag);
545                 printf("    Baudrate  = %lu\n",
546                     ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low);
547                 gas = &ent->address;
548                 printf("    Addr space= %u\n", gas->addr_space);
549                 printf("    Bit width = %u\n", gas->bit_width);
550                 printf("    Bit offset= %u\n", gas->bit_offset);
551                 printf("    Address   = 0x%016lx\n",
552                     ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low);
553                 printf("    PCI type  = %u\n", ent->pci_devid);
554                 printf("    PCI vndr  = %u\n", ent->pci_vendor);
555                 printf("    IRQ       = %u\n", ent->irq);
556                 printf("    PClock    = %u\n", ent->pclock);
557                 printf("    PCI iface = %u\n", ent->pci_interface);
558         }
559         printf("<EOT>\n");
560         return (CMD_OK);
561 }