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