static int get_off_size(int argc, char *argv[], loff_t *off, loff_t *size) { if (argc >= 1) { if (!(str2longlong(argv[0], (unsigned long long*)off))) { store_msg("'%s' is not a number\n", argv[0]); return -1; } } else { *off = 0; *size = 0; } if (argc >= 2) { if (!(str2longlong(argv[1], (unsigned long long *)size))) { store_msg("'%s' is not a number\n", argv[1]); return -1; } }else{ *size = 0; } store_dbg("offset 0x%llx, size 0x%llx", *off, *size); return 0; }
static int arg_off_size(int argc, char *argv[], uint64_t chipsize, uint64_t *off, uint64_t *size) { if (argc >= 1) { if (!(str2longlong(argv[0], (unsigned long long *)off))) { aml_nand_dbg("'%s' is not a number", argv[0]); return -1; } } else *off = 0; if (argc >= 2) { if (!(str2longlong(argv[1], (unsigned long long *)size))) { aml_nand_dbg("'%s' is not a number", argv[1]); return -1; } } else *size = chipsize - *off; if (*size == chipsize) aml_nand_dbg("whole chip/dev"); else aml_nand_dbg("offset 0x%llx, size 0x%llx", *off, *size); return 0; }
static int arg_off_size(int argc, char *argv[], nand_info_t *nand, uint64_t *off, uint64_t *size) { int idx = nand_curr_device; #if defined(CONFIG_CMD_MTDPARTS) struct mtd_device *dev; struct part_info *part; u8 pnum; if (argc >= 1 && !(str2longlong(argv[0], off))) { if ((mtdparts_init() == 0) && (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { if (dev->id->type != MTD_DEV_TYPE_NAND) { puts("not a NAND device\n"); return -1; } *off = part->offset; if (argc >= 2) { if (!(str2longlong(argv[1], size))) { printf("'%s' is not a number\n", argv[1]); return -1; } if (*size > part->size) *size = part->size; } else { *size = part->size; } idx = dev->id->num; *nand = nand_info[idx]; goto out; } } #endif if (argc >= 1) { if (!(str2longlong(argv[0], off))) { printf("'%s' is not a number\n", argv[0]); return -1; } } else { *off = 0; } if (argc >= 2) { if (!(str2longlong(argv[1], size))) { printf("'%s' is not a number\n", argv[1]); return -1; } } else { *size = nand->size - *off; } #if defined(CONFIG_CMD_MTDPARTS) out: #endif printf("device %d ", idx); if (*size == nand->size) printf("whole chip [0x%llx]\n",nand->size); else printf("offset 0x%llx, size 0x%llx\n", *off, *size); return 0; }
/* returns size of the file in bytes if OK, otherwise a negative error */ static long long get_cached_file (const char * user_id, const char * url, const char * file_id, const char * instance_id, const char * file_name, char * file_path, sem * s, int convert_to_disk, long long limit_mb) { char tmp_digest_path [BUFSIZE]; char cached_dir [BUFSIZE]; char cached_path [BUFSIZE]; char staging_path [BUFSIZE]; char digest_path [BUFSIZE]; snprintf (file_path, BUFSIZE, "%s/%s/%s/%s", sc_instance_path, user_id, instance_id, file_name); snprintf (tmp_digest_path, BUFSIZE, "%s-digest", file_path); snprintf (cached_dir, BUFSIZE, "%s/%s/cache/%s", sc_instance_path, EUCALYPTUS_ADMIN, file_id); /* cache is in admin's directory */ snprintf (cached_path, BUFSIZE, "%s/%s", cached_dir, file_name); snprintf (staging_path, BUFSIZE, "%s-staging", cached_path); snprintf (digest_path, BUFSIZE, "%s-digest", cached_path); retry: /* under a lock, figure out the state of the file */ sem_p (sc_sem); /***** acquire lock *****/ ensure_subdirectory_exists (file_path); /* creates missing directories */ struct stat mystat; int cached_exists = ! stat (cached_path, &mystat); int staging_exists = ! stat (staging_path, &mystat); int e = ERROR; int action; enum { ABORT, VERIFY, WAIT, STAGE }; if ( staging_exists ) { action = WAIT; } else { if ( cached_exists ) { action = VERIFY; } else { action = STAGE; } } /* we return the sum of these */ long long file_size_b = 0; long long digest_size_b = 0; /* while still under lock, decide whether to cache */ int should_cache = 0; if (action==STAGE) { e = walrus_object_by_url (url, tmp_digest_path, 0); /* get the digest to see how big the file is */ if (e==OK && stat (tmp_digest_path, &mystat)) { digest_size_b = (long long)mystat.st_size; } if (e==OK) { /* pull the size out of the digest */ char * xml_file = file2str (tmp_digest_path); if (xml_file) { file_size_b = str2longlong (xml_file, "<size>", "</size>"); free (xml_file); } if (file_size_b > 0) { long long full_size_b = file_size_b+digest_size_b; if (convert_to_disk) { full_size_b += swap_size_mb*MEGABYTE + MEGABYTE; /* TODO: take into account extra padding required for disks (over partitions) */ } if ( full_size_b/MEGABYTE + 1 > limit_mb ) { logprintfl (EUCAFATAL, "error: insufficient disk capacity remaining (%lldMB) in VM Type of instance %s for component %s\n", limit_mb, instance_id, file_name); action = ABORT; } else if ( ok_to_cache (cached_path, full_size_b) ) { /* will invalidate the cache, if needed */ ensure_path_exists (cached_dir); /* creates missing directories */ should_cache = 1; if ( touch (staging_path) ) { /* indicate that we'll be caching it */ logprintfl (EUCAERROR, "error: failed to create staging file %s\n", staging_path); action = ABORT; } } } else { logprintfl (EUCAERROR, "error: failed to obtain file size from digest %s\n", url); action = ABORT; } } else { logprintfl (EUCAERROR, "error: failed to obtain digest from %s\n", url); action = ABORT; } } sem_v (sc_sem); /***** release lock *****/ switch (action) { case STAGE: logprintfl (EUCAINFO, "downloding image into %s...\n", file_path); e = walrus_image_by_manifest_url (url, file_path, 1); /* for KVM, convert partition into disk */ if (e==OK && convert_to_disk) { sem_p (s); /* for the cached disk swap==0 and ephemeral==0 as we'll append them below */ if ((e=vrun("%s %s %d %d", disk_convert_command_path, file_path, 0, 0))!=0) { logprintfl (EUCAERROR, "error: partition-to-disk image conversion command failed\n"); } sem_v (s); /* recalculate file size now that it was converted */ if ( stat (file_path, &mystat ) != 0 ) { logprintfl (EUCAERROR, "error: file %s not found\n", file_path); } else if (mystat.st_size < 1) { logprintfl (EUCAERROR, "error: file %s has the size of 0\n", file_path); } else { file_size_b = (long long)mystat.st_size; } } /* cache the partition or disk, if possible */ if ( e==OK && should_cache ) { if ( (e=vrun ("cp -a %s %s", file_path, cached_path)) != 0) { logprintfl (EUCAERROR, "failed to copy file %s into cache at %s\n", file_path, cached_path); } if ( e==OK && (e=vrun ("cp -a %s %s", tmp_digest_path, digest_path)) != 0) { logprintfl (EUCAERROR, "failed to copy digest file %s into cache at %s\n", tmp_digest_path, digest_path); } } sem_p (sc_sem); if (should_cache) { unlink (staging_path); } if ( e ) { logprintfl (EUCAERROR, "error: failed to download file from Walrus into %s\n", file_path); unlink (file_path); unlink (tmp_digest_path); if (should_cache) { unlink (cached_path); unlink (digest_path); if ( rmdir(cached_dir) ) { logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir); } } } sem_v (sc_sem); break; case WAIT: logprintfl (EUCAINFO, "waiting for disapperance of %s...\n", staging_path); /* wait for staging_path to disappear, which means both either the * download succeeded or it failed */ if ( (e=wait_for_file (NULL, staging_path, 180, "cached image")) ) return 0L; /* yes, it is OK to fall through */ case VERIFY: logprintfl (EUCAINFO, "verifying cached file in %s...\n", cached_path); sem_p (sc_sem); /***** acquire lock *****/ e = ERROR; if ( stat (cached_path, &mystat ) != 0 ) { logprintfl (EUCAERROR, "error: file %s not found\n", cached_path); } else if (mystat.st_size < 1) { logprintfl (EUCAERROR, "error: file %s has the size of 0\n", cached_path); } else if ((e=walrus_verify_digest (url, digest_path))<0) { /* negative status => digest changed */ unlink (cached_path); unlink (staging_path); /* TODO: needed? */ unlink (digest_path); if ( rmdir (cached_dir) ) { logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir); } else { logprintfl (EUCAINFO, "due to failure, removed cache directory %s\n", cached_dir); } } else { file_size_b = mystat.st_size; /* touch the digest so cache can use mtime for invalidation */ if ( touch (digest_path) ) { logprintfl (EUCAERROR, "error: failed to touch digest file %s\n", digest_path); } else if ( stat (digest_path, &mystat) ) { logprintfl (EUCAERROR, "error: digest file %s not found\n", digest_path); } else { digest_size_b = (long long)mystat.st_size; } } sem_v (sc_sem); /***** release lock *****/ if (e<0) { /* digest changed */ if (action==VERIFY) { /* i.e. we did not download/waited for this file */ /* try downloading anew */ goto retry; } else { logprintfl (EUCAERROR, "error: digest mismatch, giving up\n"); return 0L; } } else if (e>0) { /* problem with file or digest */ return 0L; } else { /* all good - copy it, finally */ ensure_subdirectory_exists (file_path); /* creates missing directories */ if ( (e=vrun ("cp -a %s %s", cached_path, file_path)) != 0) { logprintfl (EUCAERROR, "failed to copy file %s from cache at %s\n", file_path, cached_path); return 0L; } } break; case ABORT: logprintfl (EUCAERROR, "get_cached_file() failed (errno=%d)\n", e); e = ERROR; } if (e==OK && file_size_b > 0 && convert_to_disk ) { // if all went well above long long ephemeral_mb = limit_mb - swap_size_mb - (file_size_b+digest_size_b)/MEGABYTE; if ( swap_size_mb>0L || ephemeral_mb>0L ) { sem_p (s); if ((e=vrun("%s %s %lld %lld", disk_convert_command_path, file_path, swap_size_mb, ephemeral_mb))!=0) { logprintfl (EUCAERROR, "error: failed to add swap or ephemeral to the disk image\n"); } sem_v (s); /* recalculate file size (again!) now that it was converted */ if ( stat (file_path, &mystat ) != 0 ) { logprintfl (EUCAERROR, "error: file %s not found\n", file_path); } else if (mystat.st_size < 1) { logprintfl (EUCAERROR, "error: file %s has the size of 0\n", file_path); } else { file_size_b = (long long)mystat.st_size; } } } if (e==OK && action!=ABORT) return file_size_b + digest_size_b; return 0L; }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int i, dev, ret = 0; ulong addr; loff_t off, size; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); #if ((defined CONFIG_AML_NAND_KEY) || (defined MX_REVD) || (defined CONFIG_SECURE_NAND)) int chip_num , tmp_chip_num, error; nand = nand_info[nand_curr_device]; struct mtd_info *mtd =nand; struct aml_nand_chip *aml_chip = mtd_to_nand_chip(nand); #endif /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; #ifdef CONFIG_AML_NAND_KEY if (strcmp(cmd, "key") == 0){ aml_chip->key_protect = 1; //force nand key can be erased return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif if(strcmp(cmd, "exist") == 0){ if(nand_info[1]){ printf("nand exist return 0\n"); return 0; } else{ printf("nand exist return 1\n"); return 1; } } #ifdef MX_REVD if (strcmp(cmd, "errstat") == 0){ printk("checking chiprev here\n"); if(aml_chip->err_sts == NAND_CHIP_REVB_HY_ERR){ printk("Must use RevD chip for Hynix 26nm/20nm nand boot without SPI!!!\n"); return NAND_CHIP_REVB_HY_ERR; } return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif if (strcmp(cmd, "info") == 0) { #ifdef CONFIG_AML_NAND_KEY aml_chip->key_protect = 0; //protect nand key can not be erased #endif #ifdef CONFIG_SECURE_NAND aml_chip->secure_protect = 0; //protect nand secure can not be erased #endif putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { nand = nand_info[i]; if (!nand) { nand_init(); if (!nand) return -1; } if (nand->name) nand_print_info(i); } return 0; } if (strcmp(cmd, "init") == 0) { nand_init(); return 0; } //cmd for nand test , if nand is ok , then trigger power off if (strcmp(cmd, "test") == 0) { int ret=-1; puts("\ntest the nand flash ***\n"); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { nand = nand_info[i]; if (!nand) { ret=nand_test_init(); printf("\n***nand_test_init()in NAND DEVICE %d returned:%d***\n ", i,ret); if (ret) return -1; } } return 0; } if (strcmp(cmd, "scrub_detect") == 0) { if (nand_curr_device < 0 || nand_curr_device >= (CONFIG_SYS_MAX_NAND_DEVICE+2)) { puts("\nno devices available\n"); return 1; } nand = nand_info[nand_curr_device]; aml_nand_stupid_dectect_badblock(nand); return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE)) puts("no devices available\n"); else nand_print_info(nand_curr_device); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= (CONFIG_SYS_MAX_NAND_DEVICE+1) || !nand_info[dev]->name) { puts("No such device\n"); return 1; } printf("Device %d: %s", dev, nand_info[dev]->name); puts("... is now current device\n"); nand_curr_device = dev; #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev]->priv, dev); #endif return 0; } if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && strncmp(cmd, "dump", 4) != 0 && strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strncmp(cmd, "rom_protect", 11) != 0 && strncmp(cmd, "wr_rd_cmp", 9) != 0 && strncmp(cmd, "rom_write", 9) != 0 && (strncmp(cmd, "rom_read", 8) != 0) && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 && strcmp(cmd, "factory_info") != 0 && strcmp(cmd, "show_para_page")&& strncmp(cmd, "scrub_safe", 10) != 0) //my_ goto usage; /* the following commands operate on the current device */ if (nand_curr_device < 0 || nand_curr_device >= (CONFIG_SYS_MAX_NAND_DEVICE+2)) { puts("\nno devices available\n"); return 1; } nand = nand_info[nand_curr_device]; if (!nand) return -1; if (strcmp(cmd, "bad") == 0) { printf("\nDevice %d bad blocks:\n", nand_curr_device); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %09llx\n", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0 || strcmp(cmd, "scrub_safe") == 0) { nand_erase_options_t opts; int argc_cnt = 2; //printk("%s\n", argv[2]); /* if (isstring(argv[2])) { nand = get_mtd_device_nm(argv[2]); if (IS_ERR(nand)){ printf("get nand device err\n"); return 1; } argc_cnt++; } */ /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > argc_cnt && !strcmp("clean", argv[argc_cnt]); if (clean) argc_cnt++; int o = argc_cnt; int scrub = !strncmp(cmd, "scrub",10); int scrub_safe = !strncmp(cmd, "scrub_safe",10); if(scrub_safe) printf("\nNAND %s: ", scrub_safe ? "scrub_safe" : "erase"); else printf("\nNAND %s: ", scrub ? "scrub" : "erase"); if (argv[argc_cnt]) { if(!strcmp(argv[argc_cnt], "whole")) { off = 0; size = nand->size; printf("whole chip.\n"); } } else { /* skip first two or three arguments, look for offset and size */ if ((strcmp(cmd, "erase") == 0) && (argc < 3)) { goto usage; } if ((arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)) { return 1; } } memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes " "if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"); if(nand_protect) { if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; else { puts("scrub aborted\n"); return -1; } } else { puts("scrub aborted\n"); return -1; } } else { opts.scrub = 1; } } else if(scrub_safe){ puts("Warning: " "scrub_safe option will erase all " "bad blocks except factory bad blocks!\n"); opts.scrub = 2; // indicate scrub_safe } ret = nand_erase_opts(nand, &opts); printf("%s\n", ret ? "ERROR" : "OK"); #ifdef CONFIG_AML_NAND_KEY aml_chip->key_protect = 0; //protect nand key can not be erased #endif #ifdef CONFIG_SECURE_NAND aml_chip->secure_protect = 0; //protect nand secure can not be erased #endif return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; s = strchr(cmd, '.'); //off = (loff_t)simple_strtoul(argv[2], NULL, 16); if (!(str2longlong(argv[2], (unsigned long long*)(&off)))) return -1; if (s != NULL && strcmp(s, ".oob") == 0) ret = nand_dump(nand, off, 1); else ret = nand_dump(nand, off, 0); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; if (isstring(argv[2])) { nand = get_mtd_device_nm(argv[2]); if (IS_ERR(nand)) goto usage; addr = (ulong)simple_strtoul(argv[3], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: %s ", read ? "read" : "write", argv[2]); if (argc == 4) { extern unsigned int get_mtd_size(char *name); off = 0; size = get_mtd_size(argv[2]); } else { if (arg_off_size(argc - 4, argv + 4, nand, &off, &size) != 0) return 1; } } else { addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; } #ifdef CONFIG_AMLROM_NANDBOOT if((read==0) && ((off)<(1024* nand->writesize)) && (nand_curr_device == 0)){ printf("offset 0x%llx in aml-boot area ,abort\n", off); return -1; } #endif s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr, 0); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr, 0); } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = size, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else if (!strcmp(s, ".raw")) {
int str2int(const char *s, unsigned int base) { return str2longlong(s, base); }