main.c revision 137978
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: head/sys/boot/ia64/efi/main.c 137978 2004-11-21 21:40:08Z marcel $"); 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 45extern char bootprog_name[]; 46extern char bootprog_rev[]; 47extern char bootprog_date[]; 48extern char bootprog_maker[]; 49 50struct efi_devdesc currdev; /* our current device */ 51struct arch_switch archsw; /* MI/MD interface boundary */ 52 53extern u_int64_t ia64_pal_entry; 54 55EFI_GUID acpi = ACPI_TABLE_GUID; 56EFI_GUID acpi20 = ACPI_20_TABLE_GUID; 57EFI_GUID devid = DEVICE_PATH_PROTOCOL; 58EFI_GUID hcdp = HCDP_TABLE_GUID; 59EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; 60EFI_GUID mps = MPS_TABLE_GUID; 61EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; 62EFI_GUID sal = SAL_SYSTEM_TABLE_GUID; 63EFI_GUID smbios = SMBIOS_TABLE_GUID; 64 65static void 66find_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 101EFI_STATUS 102main(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 182COMMAND_SET(quit, "quit", "exit the loader", command_quit); 183 184static int 185command_quit(int argc, char *argv[]) 186{ 187 exit(0); 188 return (CMD_OK); 189} 190 191COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); 192 193static int 194command_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 267COMMAND_SET(configuration, "configuration", 268 "print configuration tables", command_configuration); 269 270static const char * 271guid_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 282static int 283command_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 313COMMAND_SET(sal, "sal", "print SAL System Table", command_sal); 314 315static int 316command_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 384int 385print_trs(int type) 386{ 387 struct ia64_pal_result res; 388 int i, maxtr; 389 struct { 390 pt_entry_t pte; 391 uint64_t itir; 392 uint64_t 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 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 & 1) == 0) 436 continue; 437 438 if (!(res.pal_result[0] & 1)) 439 buf.pte &= ~PTE_AR_MASK; 440 if (!(res.pal_result[0] & 2)) 441 buf.pte &= ~PTE_PL_MASK; 442 if (!(res.pal_result[0] & 4)) 443 buf.pte &= ~PTE_DIRTY; 444 if (!(res.pal_result[0] & 8)) 445 buf.pte &= ~PTE_MA_MASK; 446 sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d %d %d %d %d " 447 "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12, 448 (buf.pte & PTE_PPN_MASK) >> 12, 449 psnames[(buf.itir & ITIR_PS_MASK) >> 2], 450 (buf.pte & PTE_ED) ? 1 : 0, 451 (int)(buf.pte & PTE_AR_MASK) >> 9, 452 (int)(buf.pte & PTE_PL_MASK) >> 7, 453 (buf.pte & PTE_DIRTY) ? 1 : 0, 454 (buf.pte & PTE_ACCESSED) ? 1 : 0, 455 manames[(buf.pte & PTE_MA_MASK) >> 2], 456 (buf.pte & PTE_PRESENT) ? 1 : 0, 457 (int)((buf.itir & ITIR_KEY_MASK) >> 8)); 458 pager_output(lbuf); 459 } 460 pager_close(); 461 462 if (res.pal_status != 0) { 463 printf("Error while getting TR contents\n"); 464 return CMD_ERROR; 465 } 466 return CMD_OK; 467} 468 469COMMAND_SET(itr, "itr", "print instruction TRs", command_itr); 470 471static int 472command_itr(int argc, char *argv[]) 473{ 474 return print_trs(0); 475} 476 477COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr); 478 479static int 480command_dtr(int argc, char *argv[]) 481{ 482 return print_trs(1); 483} 484 485COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp); 486 487static char * 488hcdp_string(char *s, u_int len) 489{ 490 static char buffer[256]; 491 492 memcpy(buffer, s, len); 493 buffer[len] = 0; 494 return (buffer); 495} 496 497static int 498command_hcdp(int argc, char *argv[]) 499{ 500 struct dig64_hcdp_table *tbl; 501 struct dig64_hcdp_entry *ent; 502 struct dig64_gas *gas; 503 int i; 504 505 tbl = efi_get_table(&hcdp); 506 if (tbl == NULL) { 507 printf("No HCDP table present\n"); 508 return (CMD_OK); 509 } 510 if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) { 511 printf("HCDP table has invalid signature\n"); 512 return (CMD_OK); 513 } 514 if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) { 515 printf("HCDP table too short\n"); 516 return (CMD_OK); 517 } 518 printf("HCDP table at 0x%016lx\n", (u_long)tbl); 519 printf("Signature = %s\n", hcdp_string(tbl->signature, 4)); 520 printf("Length = %u\n", tbl->length); 521 printf("Revision = %u\n", tbl->revision); 522 printf("Checksum = %u\n", tbl->checksum); 523 printf("OEM Id = %s\n", hcdp_string(tbl->oem_id, 6)); 524 printf("Table Id = %s\n", hcdp_string(tbl->oem_tbl_id, 8)); 525 printf("OEM rev = %u\n", tbl->oem_rev); 526 printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4)); 527 printf("Creator rev= %u\n", tbl->creator_rev); 528 printf("Entries = %u\n", tbl->entries); 529 for (i = 0; i < tbl->entries; i++) { 530 ent = tbl->entry + i; 531 printf("Entry #%d:\n", i + 1); 532 printf(" Type = %u\n", ent->type); 533 printf(" Databits = %u\n", ent->databits); 534 printf(" Parity = %u\n", ent->parity); 535 printf(" Stopbits = %u\n", ent->stopbits); 536 printf(" PCI seg = %u\n", ent->pci_segment); 537 printf(" PCI bus = %u\n", ent->pci_bus); 538 printf(" PCI dev = %u\n", ent->pci_device); 539 printf(" PCI func = %u\n", ent->pci_function); 540 printf(" Interrupt = %u\n", ent->interrupt); 541 printf(" PCI flag = %u\n", ent->pci_flag); 542 printf(" Baudrate = %lu\n", 543 ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low); 544 gas = &ent->address; 545 printf(" Addr space= %u\n", gas->addr_space); 546 printf(" Bit width = %u\n", gas->bit_width); 547 printf(" Bit offset= %u\n", gas->bit_offset); 548 printf(" Address = 0x%016lx\n", 549 ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low); 550 printf(" PCI type = %u\n", ent->pci_devid); 551 printf(" PCI vndr = %u\n", ent->pci_vendor); 552 printf(" IRQ = %u\n", ent->irq); 553 printf(" PClock = %u\n", ent->pclock); 554 printf(" PCI iface = %u\n", ent->pci_interface); 555 } 556 printf("<EOT>\n"); 557 return (CMD_OK); 558} 559