1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * VxWorks Boot Commands File: ui_vxboot.c 5 * 6 * Commands useful to people booting VxWorks 7 * 8 * Author: Mitch Lichtenberg 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47 48#include "cfe.h" 49 50#include "ui_command.h" 51 52#include "cfe_fileops.h" 53#include "cfe_loader.h" 54#include "cfe_bootblock.h" 55#include "cfe_boot.h" 56 57#include "env_subr.h" 58 59#include "net_ebuf.h" 60#include "net_ether.h" 61#include "net_enet.h" 62#include "net_ip.h" 63#include "net_api.h" 64 65#include "addrspace.h" 66 67typedef struct vxflash_s { 68 char *device; 69 char *filesys; 70} vxflash_t; 71 72static vxflash_t vxflash_default[] = { 73 { "flash3.vxworks", "fat" }, 74 { "flash3.fatfs", "fat" }, 75 { "flash1.user", "fat" }, 76 { "flash0.os", "fat" }, 77 { NULL,NULL } 78}; 79 80/* Magic address (usually in NVRAM) where to store MAC address */ 81char *vxboot_mac_addr; 82char *vxboot_mac_env = "ETH0_HWADDR"; 83 84/* 85 * XXX should probably go somewhere else 86 */ 87 88#define BOOT_LINE_ADDRS_PPC 0x4200 89#define BOOT_LINE_ADDRS_MIPS 0x700 90 91int ui_init_vxbootcmds(void); 92static int ui_cmd_vxboot_M(ui_cmdline_t *cmd,int argc,char *argv[]); 93static int ui_cmd_vxboot_p(ui_cmdline_t *cmd,int argc,char *argv[]); 94static int ui_cmd_vxboot_c(ui_cmdline_t *cmd,int argc,char *argv[]); 95static int ui_cmd_vxboot_go(ui_cmdline_t *cmd,int argc,char *argv[]); 96 97extern cfe_loadargs_t cfe_loadargs; 98 99typedef struct vxkey_s { 100 char *name; 101 char *description; 102 int num; 103} vxkey_t; 104 105typedef struct vxval_s { 106 char *name; 107 char *val; 108} vxval_t; 109 110#define MAXVXKEYS 16 111typedef struct vxbootline_s { 112 char *bootline; /* strdup of entire bootline */ 113 vxval_t vals[MAXVXKEYS+1]; /* Stuff we parsed */ 114} vxbootline_t; 115 116 117static char *vxboot_envname = "vxboot"; 118 119static vxkey_t validvxkeys[] = { 120 /* These keys go in the first token of the boot line */ 121 {"!bd","boot device"}, 122 {"!un","unit number"}, 123 {"!pn","processor number"}, 124 {"!hn","host name"}, 125 {"!fn","file name"}, 126 127 /* These keys go on the rest of the boot line */ 128 {"e","inet on ethernet (e)"}, 129 {"h","host inet (h)"}, 130 {"g","gateway inet (g)"}, 131 {"u","user (u)"}, 132 {"pw","ftp password (pw)"}, 133 {"f","flags (f)"}, 134 {"tn","target name (tn)"}, 135 {"s","startup script (s)"}, 136 {"o","other (o)"}, 137 {NULL,NULL,0}}; 138 139 140#define VXFS_FLASH 0 141#define VXFS_ETH 1 142 143static vxkey_t *vxboot_findkey(char *name) 144{ 145 vxkey_t *key = validvxkeys; 146 147 while (key->description) { 148 if (key->name && strcmp(name,key->name) == 0) return key; 149 key++; 150 } 151 152 return NULL; 153} 154 155static vxval_t *vxboot_findval(vxbootline_t *info,char *name) 156{ 157 vxval_t *val = info->vals; 158 159 while (val->name) { 160 if (strcmp(name,val->name) == 0) return val; 161 val++; 162 } 163 164 return NULL; 165} 166 167static char *vxboot_getval(vxbootline_t *info,char *name,char *def) 168{ 169 vxval_t *val = vxboot_findval(info,name); 170 if (!val) return def; 171 return val->val; 172} 173 174static int vxboot_init(vxbootline_t *info,char *str) 175{ 176 memset(info,0,sizeof(vxbootline_t)); 177 info->bootline = lib_strdup(str); 178 179 if (!info->bootline) return -1; 180 return 0; 181} 182 183static void vxboot_free(vxbootline_t *info) 184{ 185 vxval_t *val; 186 187 if (info->bootline) { 188 KFREE(info->bootline); 189 } 190 191 val = info->vals; 192 while (val->name) { 193 if (val->val) KFREE(val->val); 194 val++; 195 } 196 memset(info,0,sizeof(vxbootline_t)); 197} 198 199static int vxboot_addkey(vxbootline_t *info,char *name,char *val) 200{ 201 int idx; 202 203 for (idx = 0; idx < MAXVXKEYS; idx++) { 204 if (!info->vals[idx].name) break; 205 if (strcmp(info->vals[idx].name,name) == 0) break; 206 } 207 if (idx == MAXVXKEYS) return -1; /* no more room */ 208 209 info->vals[idx].name = name; 210 if (info->vals[idx].val) KFREE(info->vals[idx].val); 211 info->vals[idx].val = lib_strdup(val); 212 return 0; 213} 214 215 216static int vxboot_parse(vxbootline_t *info) 217{ 218 char *x,*y; 219 char *ptr; 220 char *tok; 221 222 ptr = info->bootline; /* start hacking it up */ 223 224 tok = lib_gettoken(&ptr); /* first token is the boot file */ 225 226 if (!tok) return 0; /* an empty booline is ok */ 227 228 /* 229 * Format of the first token is as follows: 230 * 231 * bootdev(unit,proc)host:filename 232 */ 233 234 235 x = tok; 236 237 /* find end of boot device name */ 238 while (*tok && (*tok != '(')) tok++; 239 if (!*tok) goto error; 240 *tok++ = '\0'; 241 242 vxboot_addkey(info,"!bd",x); /* add boot device */ 243 244 x = strchr(tok,')'); 245 if (!x) goto error; /* no close parens */ 246 *x++ = '\0'; 247 248 /* Okay, 'tok' now points at the stuff between the parens. */ 249 if ((y = strchr(tok,','))) { 250 *y++ = '\0'; 251 vxboot_addkey(info,"!un",tok); 252 vxboot_addkey(info,"!pn",y); 253 } 254 else { 255 vxboot_addkey(info,"!un",tok); 256 vxboot_addkey(info,"!pn","0"); 257 } 258 tok = x; 259 260 /* 'tok' now points at the stuff just beyond the right paren */ 261 262 if ((x = strchr(tok,':'))) { 263 *x++ = '\0'; 264 vxboot_addkey(info,"!hn",tok); 265 vxboot_addkey(info,"!fn",x); 266 } 267 else { 268 goto error; 269 } 270 271 /* Now parse the rest of the bootline params */ 272 273 while ((tok = gettoken(&ptr))) { 274 if ((x = strchr(tok,'='))) { 275 *x++ = '\0'; 276 if (vxboot_addkey(info,tok,x) < 0) break; 277 } 278 } 279 280 return 0; 281 282error: 283 return -1; 284} 285 286 287static void vxboot_show(vxbootline_t *info) 288{ 289 vxval_t *val; 290 vxkey_t *key; 291 char buf[50]; 292 293 val = info->vals; 294 295 while (val->name) { 296 key = vxboot_findkey(val->name); 297 if (key) { 298 printf("%-20s : %s\n",key->description,val->val); 299 } 300 else { 301 sprintf(buf,"value '%s'",val->name); 302 printf("%20s : %s\n",buf,val->val); 303 } 304 val++; 305 } 306} 307 308static int vxboot_genbootline(vxbootline_t *info) 309{ 310 char buffer[1000]; 311 char *p; 312 char *unk = "unknown"; 313 vxval_t *val; 314 315 /* Regenerate boot line */ 316 if (info->bootline) KFREE(info->bootline); 317 info->bootline = NULL; 318 319 p = buffer; 320 p += sprintf(p,"%s(%s,%s)%s:%s", 321 vxboot_getval(info,"!bd",unk), 322 vxboot_getval(info,"!un",unk), 323 vxboot_getval(info,"!pn",unk), 324 vxboot_getval(info,"!hn",unk), 325 vxboot_getval(info,"!fn",unk)); 326 327 val = info->vals; 328 329 while (val->name) { 330 if ((val->name[0] != '!') && (val->val[0])) { /* names starting with ! are special */ 331 p += sprintf(p," %s=%s",val->name,val->val); 332 } 333 val++; 334 } 335 336 info->bootline = lib_strdup(buffer); 337 338 return 0; 339} 340 341static int vxboot_net_config(vxbootline_t *info) 342{ 343 uint8_t netmask[IP_ADDR_LEN]; 344 char *p, *ipstr, tmp; 345 char netcmd[128]; 346 int i; 347 348 if ((p = vxboot_getval(info,"e",NULL)) == NULL) { 349 return -1; 350 } 351 if ((ipstr = strdup(p)) == NULL) { 352 return -1; 353 } 354 355 /* Extract network mask */ 356 memset(netmask,0,sizeof(netmask)); 357 if ((p = strchr(ipstr,':')) != NULL) { 358 *p++ = 0; 359 if (strlen(p) == 8) { 360 for (i = 0; i < IP_ADDR_LEN; i++) { 361 tmp = p[2]; 362 p[2] = 0; 363 netmask[i] = lib_xtoi(p); 364 p[2] = tmp; 365 p += 2; 366 } 367 } 368 } 369 370 /* Create command line */ 371 sprintf(netcmd,"ifconfig eth0 -addr=%s -mask=%d.%d.%d.%d",ipstr, 372 netmask[0],netmask[1],netmask[2],netmask[3]); 373 if ((p = vxboot_getval(info,"g",NULL)) != NULL) { 374 sprintf(&netcmd[strlen(netcmd)]," -gw=%s",p); 375 } 376 377 /* Run through standard command line parser */ 378 ui_docommand(netcmd); 379 380 KFREE(ipstr); 381 return 0; 382} 383 384static int ui_cmd_vxboot_M(ui_cmdline_t *cmd,int argc,char *argv[]) 385{ 386 char *x; 387 uint8_t hwaddr[ENET_ADDR_LEN]; 388 389 if ((x = cmd_getarg(cmd,0)) != NULL) { 390 if (strlen(x) == 17 && enet_parse_hwaddr(x,hwaddr) == 0) { 391 env_setenv(vxboot_mac_env,x,ENV_FLG_NORMAL); 392 } 393 else { 394 printf("MAC address syntax error\n"); 395 return -1; 396 } 397 } 398 else if ((x = env_getenv(vxboot_mac_env)) != NULL) { 399 printf("MAC address: %s\n",x); 400 } 401 else { 402 printf("MAC address not configured\n"); 403 } 404 405 return 0; 406} 407 408static int ui_cmd_vxboot_p(ui_cmdline_t *cmd,int argc,char *argv[]) 409{ 410 char *x; 411 vxbootline_t info; 412 413 x = env_getenv(vxboot_envname); 414 if (!x) x = ""; 415 416 vxboot_init(&info,x); 417 if (vxboot_parse(&info) < 0) { 418 printf("Warning: Current boot line does not appear to be valid\n"); 419 } 420 vxboot_show(&info); 421 vxboot_free(&info); 422 423 return 0; 424} 425 426static int ui_cmd_vxboot_c(ui_cmdline_t *cmd,int argc,char *argv[]) 427{ 428 char *x; 429 vxbootline_t info; 430 vxval_t *val; 431 int keyidx = 0; 432 int editing = 1; 433 char buffer[500]; 434 char prompt[80]; 435 436 x = env_getenv(vxboot_envname); 437 if (!x) x = ""; 438 439 vxboot_init(&info,x); 440 if (vxboot_parse(&info) < 0) { 441 printf("Warning: Current boot line does not appear to be valid\n"); 442 } 443 444 printf("Type '-' to move to previous field, or press ENTER to accept each value\n"); 445 446 while (editing) { 447 if (validvxkeys[keyidx].name == NULL) break; 448 if (keyidx < 0) { 449 vxboot_free(&info); 450 return 0; 451 } 452 453 /* Emulate perculiar VxBoot behavior */ 454 if (strcmp(validvxkeys[keyidx].name,"!un") == 0) { 455 keyidx++; 456 continue; 457 } 458 459 sprintf(prompt,"%20s : ",validvxkeys[keyidx].description); 460 461 buffer[0] = '\0'; 462 if ((val = vxboot_findval(&info,validvxkeys[keyidx].name))) { 463 strcpy(buffer,val->val); 464 } 465 466 /* Emulate perculiar VxBoot behavior */ 467 if (strcmp(validvxkeys[keyidx].name,"!bd") == 0 && 468 memcmp(buffer,"flash",5) != 0) { 469 strcat(buffer,vxboot_getval(&info,"!un","0")); 470 } 471 472 console_readline_default(prompt,buffer,sizeof(buffer)); 473 if (buffer[0] && buffer[strlen(buffer)-1] == '-') { 474 keyidx--; 475 476 /* Emulate perculiar VxBoot behavior */ 477 if (keyidx >= 0 && strcmp(validvxkeys[keyidx].name,"!un") == 0) { 478 keyidx--; 479 } 480 481 continue; 482 } 483 484 /* Emulate perculiar VxBoot behavior */ 485 if (strcmp(validvxkeys[keyidx].name,"!bd") == 0 && buffer[0]) { 486 x = &buffer[strlen(buffer)-1]; 487 if (*x < '0' || *x > '9') { 488 vxboot_addkey(&info,"!un","0"); 489 } 490 else { 491 vxboot_addkey(&info,"!un",x); 492 *x = 0; 493 } 494 } 495 496 vxboot_addkey(&info,validvxkeys[keyidx].name,buffer); 497 keyidx++; 498 } 499 500 501 vxboot_genbootline(&info); 502 503 env_setenv(vxboot_envname,info.bootline,ENV_FLG_NORMAL); 504 505 vxboot_free(&info); 506 507 env_save(); 508 509 return 0; 510} 511 512 513static int ui_cmd_vxboot_go(ui_cmdline_t *cmd,int argc,char *argv[]) 514{ 515 char *x; 516 char *f; 517 char *p0, *p1; 518 vxbootline_t info; 519 char filename[256]; 520 char devname[32]; 521 cfe_loadargs_t *la = &cfe_loadargs; 522 vxflash_t *vxflash; 523 fileio_ctx_t *fsctx; 524 int res; 525 526 x = env_getenv(vxboot_envname); 527 if (!x) { 528 printf("VxWorks boot line has not been set. Use the 'c' command to create a boot line\n"); 529 return -1; 530 } 531 532 vxboot_init(&info,x); 533 if (vxboot_parse(&info) < 0) { 534 printf("Error: not a valid VxWorks boot line: %s.\n Use the 'c' command to edit the boot line\n",x); 535 } 536 537 /* Copy boot line to the magic place */ 538 p0 = NULL; 539 if (strcmp(CPUCFG_ARCHNAME, "PPC") == 0) { 540 p0 = (char *) KERNADDR(BOOT_LINE_ADDRS_PPC); 541 strcpy(p0,x); 542 } 543 else if (strcmp(CPUCFG_ARCHNAME, "MIPS") == 0) { 544 p0 = (char *) KERNADDR(BOOT_LINE_ADDRS_MIPS); 545 strcpy(p0,x); 546 } 547 else { 548 printf("Error: unsupported architecture for VxWorks\n"); 549 } 550 /* Add MAC addres to 'other' */ 551 if (p0 != NULL) { 552 if ((p1 = env_getenv(vxboot_mac_env)) != NULL && strlen(p1) == 17) { 553 if (vxboot_findval(&info,"o") == NULL) { 554 strcat(p0," o="); 555 } 556 strcat(p0,";mac="); 557 strcat(p0,p1); 558 /* MAC address separator must be colon (:) */ 559 p1 = &p0[strlen(p0)-17]; 560 p1[2] = p1[5] = p1[8] = p1[11] = p1[14] = ':'; 561 } 562 } 563 /* Also store MAC in magic place if provided */ 564 if (vxboot_mac_addr != NULL) { 565 if ((p1 = env_getenv(vxboot_mac_env)) != NULL) { 566 enet_parse_hwaddr(p1,(uint8_t *)vxboot_mac_addr); 567 } 568 } 569 570 /* Load the image. */ 571 la->la_filesys = NULL; 572 la->la_loader = "elf"; 573 la->la_options = NULL; 574 la->la_flags = LOADFLG_NOISY | LOADFLG_EXECUTE; 575 576 x = vxboot_getval(&info,"!bd",NULL); 577 if (!x) goto error; 578 if (strcmp(x,"sbe") == 0 || strcmp(x,"bc") == 0 || memcmp(x,"et", 2) == 0) { 579 la->la_device = "eth0"; 580 la->la_filesys = "tftp"; 581 f = vxboot_getval(&info,"h",NULL); 582 if (!f) f = vxboot_getval(&info,"!hn",""); 583 sprintf(filename,"%s:%s",f,vxboot_getval(&info,"!fn","")); 584 } 585 else if (strcmp(x,"flash") == 0) { 586 vxflash = &vxflash_default[0]; 587 while (vxflash->device) { 588 la->la_device = vxflash->device; 589 la->la_filesys = vxflash->filesys; 590 if (fs_init(la->la_filesys,&fsctx,la->la_device) == CFE_OK) { 591 fs_uninit(fsctx); 592 break; 593 } 594 vxflash++; 595 } 596 sprintf(filename,"%s",vxboot_getval(&info,"!fn","")); 597 } 598 else if (memcmp(x,"flash",5) == 0) { 599 strncpy(devname,x,sizeof(devname)-1); 600 devname[sizeof(devname)-1] = 0; 601 la->la_device = devname; 602 la->la_filesys = "fat"; 603 sprintf(filename,"%s",vxboot_getval(&info,"!fn","")); 604 } 605 606 if (vxboot_getval(&info,"e",NULL) != NULL) { 607 vxboot_net_config(&info); 608 } 609 610 la->la_filename = filename; 611#if CFG_ZLIB 612 if (strlen(filename) > 3 && 613 strcmp(&filename[strlen(filename)-3], ".gz") == 0) { 614 printf("Assuming compressed image\n"); 615 la->la_flags |= LOADFLG_COMPRESSED; 616 } 617#endif 618 vxboot_free(&info); 619 620 /* Call the loader. */ 621 /* Run the image. */ 622 res = cfe_boot(la->la_loader,la); 623 624 if (res < 0) ui_showerror(res,"Could not load image %s",filename); 625 626 /* Should not return here. */ 627 628 return res; 629 630error: 631 printf("Incorrect or invalid fields in VxWorks boot line\n"); 632 vxboot_free(&info); 633 return -1; 634} 635 636 637 638 639 640int ui_init_vxbootcmds(void) 641{ 642 cmd_addcmd("M", 643 ui_cmd_vxboot_M, 644 NULL, 645 "M [xx:xx:xx:xx:xx:xx]\n\n" 646 "Show or set Ethernet MAC address", 647 "This command reads or writes the environment variable 'ETH0_HWADDR',\n" 648 "and is provided for VxWorks boot loader compatibility.", 649 ""); 650 651 cmd_addcmd("p", 652 ui_cmd_vxboot_p, 653 NULL, 654 "Parse and display VxWorks boot string", 655 "This command reads the environent variable 'vxboot', if defined, and\n" 656 "breaks out the fields for easy display. You can change the vxworks boot\n" 657 "string with the 'c' command.", 658 ""); 659 660 cmd_addcmd("c", 661 ui_cmd_vxboot_c, 662 NULL, 663 "Change the VxWorks boot string", 664 "This command changes the environent variable 'vxboot', prompting for\n" 665 "the fields. The 'vxboot' string is committed to NVRAM.", 666 ""); 667 668 cmd_addcmd("@", 669 ui_cmd_vxboot_go, 670 NULL, 671 "Boot VxWorks", 672 "This command copies the 'vxboot' string to the architecture-dependent area\n" 673 "and transfers control to VxWorks.", 674 ""); 675 676 return 0; 677} 678 679 680