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