1 /* $NetBSD: main.c,v 1.9 2014/03/25 18:35:33 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 5 * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 32 #include <lib/libsa/stand.h> 33 #include <lib/libsa/loadfile.h> 34 35 #include <machine/sal.h> 36 #include <machine/pal.h> 37 #include <machine/pte.h> 38 #include <machine/dig64.h> 39 40 #include <efi.h> 41 #include <efilib.h> 42 #include <efifsdev.h> 43 44 #include "bootstrap.h" 45 #include "efiboot.h" 46 47 extern char bootprog_name[]; 48 extern char bootprog_rev[]; 49 50 struct efi_devdesc currdev; /* our current device */ 51 struct arch_switch archsw; /* MI/MD interface boundary */ 52 53 vaddr_t ia64_unwindtab; 54 vsize_t ia64_unwindtablen; 55 56 extern u_int64_t ia64_pal_entry; 57 58 EFI_GUID acpi = ACPI_TABLE_GUID; 59 EFI_GUID acpi20 = ACPI_20_TABLE_GUID; 60 EFI_GUID devid = DEVICE_PATH_PROTOCOL; 61 EFI_GUID hcdp = HCDP_TABLE_GUID; 62 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; 63 EFI_GUID mps = MPS_TABLE_GUID; 64 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; 65 EFI_GUID sal = SAL_SYSTEM_TABLE_GUID; 66 EFI_GUID smbios = SMBIOS_TABLE_GUID; 67 68 static void 69 find_pal_proc(void) 70 { 71 int i; 72 struct sal_system_table *saltab = 0; 73 static int sizes[6] = { 74 48, 32, 16, 32, 16, 16 75 }; 76 u_int8_t *p; 77 78 saltab = efi_get_table(&sal); 79 if (saltab == NULL) { 80 printf("Can't find SAL System Table\n"); 81 return; 82 } 83 84 if (memcmp(saltab->sal_signature, "SST_", 4)) { 85 printf("Bad signature for SAL System Table\n"); 86 return; 87 } 88 89 p = (u_int8_t *) (saltab + 1); 90 for (i = 0; i < saltab->sal_entry_count; i++) { 91 if (*p == 0) { 92 struct sal_entrypoint_descriptor *dp; 93 dp = (struct sal_entrypoint_descriptor *) p; 94 ia64_pal_entry = dp->sale_pal_proc; 95 return; 96 } 97 p += sizes[*p]; 98 } 99 100 printf("Can't find PAL proc\n"); 101 return; 102 } 103 104 EFI_STATUS 105 main(int argc, CHAR16 *argv[]) 106 { 107 EFI_LOADED_IMAGE *img; 108 int i; 109 110 /* 111 * XXX Chicken-and-egg problem; we want to have console output 112 * early, but some console attributes may depend on reading from 113 * eg. the boot device, which we can't do yet. We can use 114 * printf() etc. once this is done. 115 */ 116 cons_probe(); 117 118 /* 119 * Initialise the block cache 120 */ 121 /* bcache_init(32, 512); */ /* 16k XXX tune this */ 122 123 find_pal_proc(); 124 125 efifs_dev_init(); 126 127 /* efinet_init_driver(); XXX enable net boot. */ 128 129 /* Get our loaded image protocol interface structure. */ 130 BS->HandleProtocol(IH, &imgid, (VOID**)&img); 131 132 printf("Image base: 0x%lx\n", (u_long)img->ImageBase); 133 134 printf("\n"); 135 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 136 137 i = efifs_get_unit(img->DeviceHandle); 138 if (i >= 0) { 139 currdev.d_dev = &devsw[0]; /* XXX disk */ 140 currdev.d_kind.efidisk.unit = i; 141 /* XXX should be able to detect this, default to autoprobe */ 142 currdev.d_kind.efidisk.slice = -1; 143 currdev.d_kind.efidisk.partition = 0; 144 currdev.d_type = DEVT_DISK; 145 } else { 146 currdev.d_dev = &devsw[1]; /* XXX net */ 147 currdev.d_kind.netif.unit = 0; /* XXX */ 148 currdev.d_type = DEVT_NET; 149 150 } 151 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 (ev_sethook_t *) 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 = alloc(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 snprintf(buf, sizeof(buf), 276 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 277 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 278 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 279 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 280 return (buf); 281 } 282 283 static int 284 command_configuration(int argc, char *argv[]) 285 { 286 int i; 287 288 printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries); 289 for (i = 0; i < ST->NumberOfTableEntries; i++) { 290 EFI_GUID *guid; 291 292 printf(" "); 293 guid = &ST->ConfigurationTable[i].VendorGuid; 294 if (!memcmp(guid, &mps, sizeof(EFI_GUID))) 295 printf("MPS Table"); 296 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) 297 printf("ACPI Table"); 298 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) 299 printf("ACPI 2.0 Table"); 300 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) 301 printf("SMBIOS Table"); 302 else if (!memcmp(guid, &sal, sizeof(EFI_GUID))) 303 printf("SAL System Table"); 304 else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID))) 305 printf("DIG64 HCDP Table"); 306 else 307 printf("Unknown Table (%s)", guid_to_string(guid)); 308 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); 309 } 310 311 return CMD_OK; 312 } 313 314 COMMAND_SET(sal, "sal", "print SAL System Table", command_sal); 315 316 static int 317 command_sal(int argc, char *argv[]) 318 { 319 int i; 320 struct sal_system_table *saltab = 0; 321 static int sizes[6] = { 322 48, 32, 16, 32, 16, 16 323 }; 324 u_int8_t *p; 325 326 saltab = efi_get_table(&sal); 327 if (saltab == NULL) { 328 printf("Can't find SAL System Table\n"); 329 return CMD_ERROR; 330 } 331 332 if (memcmp(saltab->sal_signature, "SST_", 4)) { 333 printf("Bad signature for SAL System Table\n"); 334 return CMD_ERROR; 335 } 336 337 printf("SAL Revision %x.%02x\n", 338 saltab->sal_rev[1], 339 saltab->sal_rev[0]); 340 printf("SAL A Version %x.%02x\n", 341 saltab->sal_a_version[1], 342 saltab->sal_a_version[0]); 343 printf("SAL B Version %x.%02x\n", 344 saltab->sal_b_version[1], 345 saltab->sal_b_version[0]); 346 347 p = (u_int8_t *) (saltab + 1); 348 for (i = 0; i < saltab->sal_entry_count; i++) { 349 printf(" Desc %d", *p); 350 if (*p == 0) { 351 struct sal_entrypoint_descriptor *dp; 352 dp = (struct sal_entrypoint_descriptor *) p; 353 printf("\n"); 354 printf(" PAL Proc at 0x%lx\n", 355 dp->sale_pal_proc); 356 printf(" SAL Proc at 0x%lx\n", 357 dp->sale_sal_proc); 358 printf(" SAL GP at 0x%lx\n", 359 dp->sale_sal_gp); 360 } else if (*p == 1) { 361 struct sal_memory_descriptor *dp; 362 dp = (struct sal_memory_descriptor *) p; 363 printf(" Type %d.%d, ", 364 dp->sale_memory_type[0], 365 dp->sale_memory_type[1]); 366 printf("Address 0x%lx, ", 367 dp->sale_physical_address); 368 printf("Length 0x%x\n", 369 dp->sale_length); 370 } else if (*p == 5) { 371 struct sal_ap_wakeup_descriptor *dp; 372 dp = (struct sal_ap_wakeup_descriptor *) p; 373 printf("\n"); 374 printf(" Mechanism %d\n", dp->sale_mechanism); 375 printf(" Vector 0x%lx\n", dp->sale_vector); 376 } else 377 printf("\n"); 378 379 p += sizes[*p]; 380 } 381 382 return CMD_OK; 383 } 384 385 int 386 print_trs(int type) 387 { 388 struct ia64_pal_result res; 389 int i, maxtr; 390 struct { 391 pt_entry_t pte; 392 uint64_t itir; 393 uint64_t ifa; 394 struct ia64_rr rr; 395 } buf; 396 static const char *psnames[] = { 397 "1B", "2B", "4B", "8B", 398 "16B", "32B", "64B", "128B", 399 "256B", "512B", "1K", "2K", 400 "4K", "8K", "16K", "32K", 401 "64K", "128K", "256K", "512K", 402 "1M", "2M", "4M", "8M", 403 "16M", "32M", "64M", "128M", 404 "256M", "512M", "1G", "2G" 405 }; 406 static const char *manames[] = { 407 "WB", "bad", "bad", "bad", 408 "UC", "UCE", "WC", "NaT", 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 memset(&buf, 0, 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 & 1) == 0) 437 continue; 438 439 if (!(res.pal_result[0] & 1)) 440 buf.pte &= ~PTE_AR_MASK; 441 if (!(res.pal_result[0] & 2)) 442 buf.pte &= ~PTE_PL_MASK; 443 if (!(res.pal_result[0] & 4)) 444 buf.pte &= ~PTE_DIRTY; 445 if (!(res.pal_result[0] & 8)) 446 buf.pte &= ~PTE_MA_MASK; 447 snprintf(lbuf, sizeof(lbuf), 448 "%03d %06x %013lx %013lx %4s %d %d %d %d %d " 449 "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12, 450 (buf.pte & PTE_PPN_MASK) >> 12, 451 psnames[(buf.itir & ITIR_PS_MASK) >> 2], 452 (buf.pte & PTE_ED) ? 1 : 0, 453 (int)(buf.pte & PTE_AR_MASK) >> 9, 454 (int)(buf.pte & PTE_PL_MASK) >> 7, 455 (buf.pte & PTE_DIRTY) ? 1 : 0, 456 (buf.pte & PTE_ACCESSED) ? 1 : 0, 457 manames[(buf.pte & PTE_MA_MASK) >> 2], 458 (buf.pte & PTE_PRESENT) ? 1 : 0, 459 (int)((buf.itir & ITIR_KEY_MASK) >> 8)); 460 pager_output(lbuf); 461 } 462 pager_close(); 463 464 if (res.pal_status != 0) { 465 printf("Error while getting TR contents\n"); 466 return CMD_ERROR; 467 } 468 return CMD_OK; 469 } 470 471 COMMAND_SET(itr, "itr", "print instruction TRs", command_itr); 472 473 static int 474 command_itr(int argc, char *argv[]) 475 { 476 return print_trs(0); 477 } 478 479 COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr); 480 481 static int 482 command_dtr(int argc, char *argv[]) 483 { 484 return print_trs(1); 485 } 486 487 COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp); 488 489 static char * 490 hcdp_string(char *s, u_int len) 491 { 492 static char buffer[256]; 493 494 memcpy(buffer, s, len); 495 buffer[len] = 0; 496 return (buffer); 497 } 498 499 static int 500 command_hcdp(int argc, char *argv[]) 501 { 502 struct dig64_hcdp_table *tbl; 503 union dev_desc *desc; 504 int i, m, n; 505 506 tbl = efi_get_table(&hcdp); 507 if (tbl == NULL) { 508 printf("No HCDP table present\n"); 509 return (CMD_OK); 510 } 511 if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) { 512 printf("HCDP table has invalid signature\n"); 513 return (CMD_OK); 514 } 515 printf("HCDP table at 0x%lx\n", (u_long)tbl); 516 printf("Signature = %s\n", hcdp_string(tbl->signature, 4)); 517 printf("Length = %u\n", tbl->length); 518 printf("Revision = %u\n", tbl->revision); 519 printf("Checksum = %u\n", tbl->checksum); 520 printf("OEM Id = %s\n", hcdp_string(tbl->oem_id, 6)); 521 printf("Table Id = %s\n", hcdp_string(tbl->oem_tbl_id, 8)); 522 printf("OEM rev = %u\n", tbl->oem_rev); 523 printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4)); 524 printf("Creator rev= %u\n", tbl->creator_rev); 525 printf("Entries = %u\n", tbl->entries); 526 n = 0; 527 m = tbl->length - sizeof(struct dig64_hcdp_table); 528 i = 1; 529 while (n < m) { 530 printf("Entry #%d:\n", i); 531 desc = (union dev_desc *)((char *)tbl->entry + n); 532 printf(" Type = %u\n", desc->type); 533 if (desc->type == DIG64_ENTRYTYPE_TYPE0 || 534 desc->type == DIG64_ENTRYTYPE_TYPE1) { 535 struct dig64_hcdp_entry *ent = &desc->uart; 536 struct dig64_gas *gas; 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) + 548 (u_long)ent->baud_low); 549 gas = &ent->address; 550 printf(" Addr space= %u\n", gas->addr_space); 551 printf(" Bit width = %u\n", gas->bit_width); 552 printf(" Bit offset= %u\n", gas->bit_offset); 553 printf(" Address = 0x%lx\n", 554 ((u_long)gas->addr_high << 32) + 555 (u_long)gas->addr_low); 556 printf(" PCI type = %u\n", ent->pci_devid); 557 printf(" PCI vndr = %u\n", ent->pci_vendor); 558 printf(" IRQ = %u\n", ent->irq); 559 printf(" PClock = %u\n", ent->pclock); 560 printf(" PCI iface = %u\n", ent->pci_interface); 561 562 n += sizeof(struct dig64_hcdp_entry); 563 } else { 564 struct dig64_pcdp_entry *pcdp = &desc->pcdp; 565 566 if (tbl->revision < 3) { 567 printf("PCDP not support\n"); 568 return (CMD_OK); 569 } 570 571 printf(" Length = %u\n", pcdp->length); 572 printf(" Index EFI = %u\n", pcdp->index); 573 printf(" Interconn = %u", pcdp->specs.type); 574 575 switch (pcdp->specs.type) { 576 case DIG64_PCDP_SPEC_ACPI: 577 { 578 struct dig64_acpi_spec *acpi = 579 &pcdp->specs.acpi; 580 581 printf("(ACPI)\n"); 582 printf(" Length = %u\n", acpi->length); 583 printf(" ACPI_UID = %x\n", acpi->uid); 584 printf(" ACPI_HID = %x\n", acpi->hid); 585 printf(" ACPI GSI = %x\n", acpi->acpi_gsi); 586 printf(" MMIO_TRA = %lx\n", acpi->mmio_tra); 587 printf(" IOPort_TRA= %lx\n", 588 acpi->ioport_tra); 589 printf(" Flags = %x\n", acpi->flags); 590 break; 591 } 592 case DIG64_PCDP_SPEC_PCI: 593 { 594 struct dig64_pci_spec *pci = &pcdp->specs.pci; 595 596 printf("(PCI)\n"); 597 printf(" Length = %u\n", pci->length); 598 printf(" Seg GrpNum= %u\n", pci->sgn); 599 printf(" Bus = %u\n", pci->bus); 600 printf(" Device = %u\n", pci->device); 601 printf(" Function = %u\n", pci->function); 602 printf(" Device ID = %u\n", pci->device_id); 603 printf(" Vendor ID = %u\n", pci->vendor_id); 604 printf(" ACPI GSI = %x\n", pci->acpi_gsi); 605 printf(" MMIO_TRA = %lx\n", pci->mmio_tra); 606 printf(" IOPort_TRA= %lx\n", 607 pci->ioport_tra); 608 printf(" Flags = %x\n", pci->flags); 609 break; 610 } 611 } 612 613 n += pcdp->length; 614 } 615 } 616 printf("<EOT>\n"); 617 return (CMD_OK); 618 } 619 620 struct bootblk_command commands[] = { 621 COMMON_COMMANDS, 622 { "quit", "exit the loader", command_quit }, 623 { "memmap", "print memory map", command_memmap }, 624 { "configuration", "print configuration tables", command_configuration }, 625 { "sal", "print SAL System Table", command_sal }, 626 { "itr", "print instruction TRs", command_itr }, 627 { "dtr", "print data TRs", command_dtr }, 628 { "hcdp", "Dump HCDP info", command_hcdp }, 629 { NULL, NULL, NULL }, 630 }; 631