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, 183 &currdev.d_unit, NULL); 184 currdev.d_type = currdev.d_dev->dv_type; 185 186 env_setenv("loaddev", EV_VOLATILE, ia64_fmtdev(&currdev), env_noset, 187 env_nounset); 188 189 dev = get_dev_option(argc, argv); 190 if (dev == NULL) 191 dev = ia64_fmtdev(&currdev); 192 193 env_setenv("currdev", EV_VOLATILE, dev, ia64_setcurrdev, env_nounset); 194 195 setenv("LINES", "24", 1); /* optional */ 196 197 archsw.arch_autoload = ia64_autoload; 198 archsw.arch_copyin = ia64_copyin; 199 archsw.arch_copyout = ia64_copyout; 200 archsw.arch_getdev = ia64_getdev; 201 archsw.arch_loadaddr = ia64_loadaddr; 202 archsw.arch_loadseg = ia64_loadseg; 203 archsw.arch_readin = ia64_readin; 204 205 interact(); /* doesn't return */ 206 207 return (EFI_SUCCESS); /* keep compiler happy */ 208} 209 210COMMAND_SET(quit, "quit", "exit the loader", command_quit); 211 212static int 213command_quit(int argc, char *argv[]) 214{ 215 exit(0); 216 /* NOTREACHED */ 217 return (CMD_OK); 218} 219 220COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 221 222static int 223command_reboot(int argc, char *argv[]) 224{ 225 226 RS->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); 227 /* NOTREACHED */ 228 return (CMD_OK); 229} 230 231COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); 232 233static int 234command_memmap(int argc, char *argv[]) 235{ 236 UINTN sz; 237 EFI_MEMORY_DESCRIPTOR *map, *p; 238 UINTN key, dsz; 239 UINT32 dver; 240 EFI_STATUS status; 241 int i, ndesc; 242 static char *types[] = { 243 "Reserved", 244 "LoaderCode", 245 "LoaderData", 246 "BootServicesCode", 247 "BootServicesData", 248 "RuntimeServicesCode", 249 "RuntimeServicesData", 250 "ConventionalMemory", 251 "UnusableMemory", 252 "ACPIReclaimMemory", 253 "ACPIMemoryNVS", 254 "MemoryMappedIO", 255 "MemoryMappedIOPortSpace", 256 "PalCode" 257 }; 258 259 sz = 0; 260 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); 261 if (status != EFI_BUFFER_TOO_SMALL) { 262 printf("Can't determine memory map size\n"); 263 return CMD_ERROR; 264 } 265 map = malloc(sz); 266 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); 267 if (EFI_ERROR(status)) { 268 printf("Can't read memory map\n"); 269 return CMD_ERROR; 270 } 271 272 ndesc = sz / dsz; 273 printf("%23s %12s %12s %8s %4s\n", 274 "Type", "Physical", "Virtual", "#Pages", "Attr"); 275 276 for (i = 0, p = map; i < ndesc; 277 i++, p = NextMemoryDescriptor(p, dsz)) { 278 printf("%23s %012lx %012lx %08lx ", 279 types[p->Type], 280 p->PhysicalStart, 281 p->VirtualStart, 282 p->NumberOfPages); 283 if (p->Attribute & EFI_MEMORY_UC) 284 printf("UC "); 285 if (p->Attribute & EFI_MEMORY_WC) 286 printf("WC "); 287 if (p->Attribute & EFI_MEMORY_WT) 288 printf("WT "); 289 if (p->Attribute & EFI_MEMORY_WB) 290 printf("WB "); 291 if (p->Attribute & EFI_MEMORY_UCE) 292 printf("UCE "); 293 if (p->Attribute & EFI_MEMORY_WP) 294 printf("WP "); 295 if (p->Attribute & EFI_MEMORY_RP) 296 printf("RP "); 297 if (p->Attribute & EFI_MEMORY_XP) 298 printf("XP "); 299 if (p->Attribute & EFI_MEMORY_RUNTIME) 300 printf("RUNTIME"); 301 printf("\n"); 302 } 303 304 return CMD_OK; 305} 306 307COMMAND_SET(configuration, "configuration", 308 "print configuration tables", command_configuration); 309 310static const char * 311guid_to_string(EFI_GUID *guid) 312{ 313 static char buf[40]; 314 315 sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 316 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 317 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 318 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 319 return (buf); 320} 321 322static int 323command_configuration(int argc, char *argv[]) 324{ 325 int i; 326 327 printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries); 328 for (i = 0; i < ST->NumberOfTableEntries; i++) { 329 EFI_GUID *guid; 330 331 printf(" "); 332 guid = &ST->ConfigurationTable[i].VendorGuid; 333 if (!memcmp(guid, &mps, sizeof(EFI_GUID))) 334 printf("MPS Table"); 335 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) 336 printf("ACPI Table"); 337 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) 338 printf("ACPI 2.0 Table"); 339 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) 340 printf("SMBIOS Table"); 341 else if (!memcmp(guid, &sal, sizeof(EFI_GUID))) 342 printf("SAL System Table"); 343 else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID))) 344 printf("DIG64 HCDP Table"); 345 else 346 printf("Unknown Table (%s)", guid_to_string(guid)); 347 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); 348 } 349 350 return CMD_OK; 351} 352 353COMMAND_SET(sal, "sal", "print SAL System Table", command_sal); 354 355static int 356command_sal(int argc, char *argv[]) 357{ 358 int i; 359 struct sal_system_table *saltab = 0; 360 static int sizes[6] = { 361 48, 32, 16, 32, 16, 16 362 }; 363 u_int8_t *p; 364 365 saltab = efi_get_table(&sal); 366 if (saltab == NULL) { 367 printf("Can't find SAL System Table\n"); 368 return CMD_ERROR; 369 } 370 371 if (memcmp(saltab->sal_signature, "SST_", 4)) { 372 printf("Bad signature for SAL System Table\n"); 373 return CMD_ERROR; 374 } 375 376 printf("SAL Revision %x.%02x\n", 377 saltab->sal_rev[1], 378 saltab->sal_rev[0]); 379 printf("SAL A Version %x.%02x\n", 380 saltab->sal_a_version[1], 381 saltab->sal_a_version[0]); 382 printf("SAL B Version %x.%02x\n", 383 saltab->sal_b_version[1], 384 saltab->sal_b_version[0]); 385 386 p = (u_int8_t *) (saltab + 1); 387 for (i = 0; i < saltab->sal_entry_count; i++) { 388 printf(" Desc %d", *p); 389 if (*p == 0) { 390 struct sal_entrypoint_descriptor *dp; 391 dp = (struct sal_entrypoint_descriptor *) p; 392 printf("\n"); 393 printf(" PAL Proc at 0x%lx\n", 394 dp->sale_pal_proc); 395 printf(" SAL Proc at 0x%lx\n", 396 dp->sale_sal_proc); 397 printf(" SAL GP at 0x%lx\n", 398 dp->sale_sal_gp); 399 } else if (*p == 1) { 400 struct sal_memory_descriptor *dp; 401 dp = (struct sal_memory_descriptor *) p; 402 printf(" Type %d.%d, ", 403 dp->sale_memory_type[0], 404 dp->sale_memory_type[1]); 405 printf("Address 0x%lx, ", 406 dp->sale_physical_address); 407 printf("Length 0x%x\n", 408 dp->sale_length); 409 } else if (*p == 5) { 410 struct sal_ap_wakeup_descriptor *dp; 411 dp = (struct sal_ap_wakeup_descriptor *) p; 412 printf("\n"); 413 printf(" Mechanism %d\n", dp->sale_mechanism); 414 printf(" Vector 0x%lx\n", dp->sale_vector); 415 } else 416 printf("\n"); 417 418 p += sizes[*p]; 419 } 420 421 return CMD_OK; 422} 423 424int 425print_trs(int type) 426{ 427 struct ia64_pal_result res; 428 int i, maxtr; 429 struct { 430 pt_entry_t pte; 431 uint64_t itir; 432 uint64_t ifa; 433 struct ia64_rr rr; 434 } buf; 435 static const char *psnames[] = { 436 "1B", "2B", "4B", "8B", 437 "16B", "32B", "64B", "128B", 438 "256B", "512B", "1K", "2K", 439 "4K", "8K", "16K", "32K", 440 "64K", "128K", "256K", "512K", 441 "1M", "2M", "4M", "8M", 442 "16M", "32M", "64M", "128M", 443 "256M", "512M", "1G", "2G" 444 }; 445 static const char *manames[] = { 446 "WB", "bad", "bad", "bad", 447 "UC", "UCE", "WC", "NaT", 448 }; 449 450 res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0); 451 if (res.pal_status != 0) { 452 printf("Can't get VM summary\n"); 453 return CMD_ERROR; 454 } 455 456 if (type == 0) 457 maxtr = (res.pal_result[0] >> 40) & 0xff; 458 else 459 maxtr = (res.pal_result[0] >> 32) & 0xff; 460 461 printf("%d translation registers\n", maxtr); 462 463 pager_open(); 464 pager_output("TR# RID Virtual Page Physical Page PgSz ED AR PL D A MA P KEY\n"); 465 for (i = 0; i <= maxtr; i++) { 466 char lbuf[128]; 467 468 bzero(&buf, sizeof(buf)); 469 res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type, 470 (u_int64_t) &buf); 471 if (res.pal_status != 0) 472 break; 473 474 /* Only display valid translations */ 475 if ((buf.ifa & 1) == 0) 476 continue; 477 478 if (!(res.pal_result[0] & 1)) 479 buf.pte &= ~PTE_AR_MASK; 480 if (!(res.pal_result[0] & 2)) 481 buf.pte &= ~PTE_PL_MASK; 482 if (!(res.pal_result[0] & 4)) 483 buf.pte &= ~PTE_DIRTY; 484 if (!(res.pal_result[0] & 8)) 485 buf.pte &= ~PTE_MA_MASK; 486 sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d %d %d %d %d " 487 "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12, 488 (buf.pte & PTE_PPN_MASK) >> 12, 489 psnames[(buf.itir & ITIR_PS_MASK) >> 2], 490 (buf.pte & PTE_ED) ? 1 : 0, 491 (int)(buf.pte & PTE_AR_MASK) >> 9, 492 (int)(buf.pte & PTE_PL_MASK) >> 7, 493 (buf.pte & PTE_DIRTY) ? 1 : 0, 494 (buf.pte & PTE_ACCESSED) ? 1 : 0, 495 manames[(buf.pte & PTE_MA_MASK) >> 2], 496 (buf.pte & PTE_PRESENT) ? 1 : 0, 497 (int)((buf.itir & ITIR_KEY_MASK) >> 8)); 498 pager_output(lbuf); 499 } 500 pager_close(); 501 502 if (res.pal_status != 0) { 503 printf("Error while getting TR contents\n"); 504 return CMD_ERROR; 505 } 506 return CMD_OK; 507} 508 509COMMAND_SET(itr, "itr", "print instruction TRs", command_itr); 510 511static int 512command_itr(int argc, char *argv[]) 513{ 514 return print_trs(0); 515} 516 517COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr); 518 519static int 520command_dtr(int argc, char *argv[]) 521{ 522 return print_trs(1); 523} 524 525COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp); 526 527static char * 528hcdp_string(char *s, u_int len) 529{ 530 static char buffer[256]; 531 532 memcpy(buffer, s, len); 533 buffer[len] = 0; 534 return (buffer); 535} 536 537static int 538command_hcdp(int argc, char *argv[]) 539{ 540 struct dig64_hcdp_table *tbl; 541 struct dig64_hcdp_entry *ent; 542 struct dig64_gas *gas; 543 int i; 544 545 tbl = efi_get_table(&hcdp); 546 if (tbl == NULL) { 547 printf("No HCDP table present\n"); 548 return (CMD_OK); 549 } 550 if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) { 551 printf("HCDP table has invalid signature\n"); 552 return (CMD_OK); 553 } 554 if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) { 555 printf("HCDP table too short\n"); 556 return (CMD_OK); 557 } 558 printf("HCDP table at 0x%016lx\n", (u_long)tbl); 559 printf("Signature = %s\n", hcdp_string(tbl->signature, 4)); 560 printf("Length = %u\n", tbl->length); 561 printf("Revision = %u\n", tbl->revision); 562 printf("Checksum = %u\n", tbl->checksum); 563 printf("OEM Id = %s\n", hcdp_string(tbl->oem_id, 6)); 564 printf("Table Id = %s\n", hcdp_string(tbl->oem_tbl_id, 8)); 565 printf("OEM rev = %u\n", tbl->oem_rev); 566 printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4)); 567 printf("Creator rev= %u\n", tbl->creator_rev); 568 printf("Entries = %u\n", tbl->entries); 569 for (i = 0; i < tbl->entries; i++) { 570 ent = tbl->entry + i; 571 printf("Entry #%d:\n", i + 1); 572 printf(" Type = %u\n", ent->type); 573 printf(" Databits = %u\n", ent->databits); 574 printf(" Parity = %u\n", ent->parity); 575 printf(" Stopbits = %u\n", ent->stopbits); 576 printf(" PCI seg = %u\n", ent->pci_segment); 577 printf(" PCI bus = %u\n", ent->pci_bus); 578 printf(" PCI dev = %u\n", ent->pci_device); 579 printf(" PCI func = %u\n", ent->pci_function); 580 printf(" Interrupt = %u\n", ent->interrupt); 581 printf(" PCI flag = %u\n", ent->pci_flag); 582 printf(" Baudrate = %lu\n", 583 ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low); 584 gas = &ent->address; 585 printf(" Addr space= %u\n", gas->addr_space); 586 printf(" Bit width = %u\n", gas->bit_width); 587 printf(" Bit offset= %u\n", gas->bit_offset); 588 printf(" Address = 0x%016lx\n", 589 ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low); 590 printf(" PCI type = %u\n", ent->pci_devid); 591 printf(" PCI vndr = %u\n", ent->pci_vendor); 592 printf(" IRQ = %u\n", ent->irq); 593 printf(" PClock = %u\n", ent->pclock); 594 printf(" PCI iface = %u\n", ent->pci_interface); 595 } 596 printf("<EOT>\n"); 597 return (CMD_OK); 598} 599 600COMMAND_SET(about, "about", "about the loader", command_about); 601 602extern uint64_t _start_plabel[]; 603 604static int 605command_about(int argc, char *argv[]) 606{ 607 EFI_LOADED_IMAGE *img; 608 609 printf("%s\n", bootprog_name); 610 printf("revision %s\n", bootprog_rev); 611 printf("built by %s\n", bootprog_maker); 612 printf("built on %s\n", bootprog_date); 613 614 printf("\n"); 615 616 BS->HandleProtocol(IH, &imgid, (VOID**)&img); 617 printf("image loaded at %p\n", img->ImageBase); 618 printf("entry at %#lx (%#lx)\n", _start_plabel[0], _start_plabel[1]); 619} 620