static void handle_uboot_env_var(enum ubenv_action action, const char * var) { const char * val; char ubv[128]; /* * If the user prepended "uboot." (which is how they usually see these * names) strip it off as a convenience. */ if (strncmp(var, "uboot.", 6) == 0) { snprintf(ubv, sizeof(ubv), "%s", &var[6]); var = ubv; } val = ub_env_get(var); if (action == UBENV_SHOW) { if (val == NULL) printf("uboot.%s is not set\n", var); else printf("uboot.%s=%s\n", var, val); } else if (action == UBENV_IMPORT) { if (val != NULL) { snprintf(ubv, sizeof(ubv), "uboot.%s", var); setenv(ubv, val, 1); } } }
static void handle_uboot_env_var(enum ubenv_action action, const char * var) { char ldvar[128]; const char *val; char *wrk; int len; /* * On an import with the variable name formatted as ldname=ubname, * import the uboot variable ubname into the loader variable ldname, * otherwise the historical behavior is to import to uboot.ubname. */ if (action == UBENV_IMPORT) { len = strcspn(var, "="); if (len == 0) { printf("name cannot start with '=': '%s'\n", var); return; } if (var[len] == 0) { strcpy(ldvar, "uboot."); strncat(ldvar, var, sizeof(ldvar) - 7); } else { len = MIN(len, sizeof(ldvar) - 1); strncpy(ldvar, var, len); ldvar[len] = 0; var = &var[len + 1]; } } /* * If the user prepended "uboot." (which is how they usually see these * names) strip it off as a convenience. */ if (strncmp(var, "uboot.", 6) == 0) { var = &var[6]; } /* If there is no variable name left, punt. */ if (var[0] == 0) { printf("empty variable name\n"); return; } val = ub_env_get(var); if (action == UBENV_SHOW) { if (val == NULL) printf("uboot.%s is not set\n", var); else printf("uboot.%s=%s\n", var, val); } else if (action == UBENV_IMPORT) { if (val != NULL) { setenv(ldvar, val, 1); } } }
int fdt_platform_load_dtb(void) { struct fdt_header *hdr; const char *s; char *p; int rv; /* * If the U-boot environment contains a variable giving the address of a * valid blob in memory, use it. The U-boot README says the right * variable for fdt data loaded into ram is fdt_addr_r, so try that * first. Board vendors also use both fdtaddr and fdt_addr names. */ s = ub_env_get("fdt_addr_r"); if (s == NULL) s = ub_env_get("fdtaddr"); if (s == NULL) s = ub_env_get("fdt_addr"); if (s != NULL && *s != '\0') { hdr = (struct fdt_header *)strtoul(s, &p, 16); if (*p == '\0') { if (fdt_load_dtb_addr(hdr) == 0) { printf("Using DTB provided by U-Boot at " "address %p.\n", hdr); return (0); } } } rv = 1; /* * Try to get FDT filename first from loader env and then from u-boot env */ s = getenv("fdt_file"); if (s == NULL) s = ub_env_get("fdtfile"); if (s == NULL) s = ub_env_get("fdt_file"); if (s != NULL && *s != '\0') { if (fdt_load_dtb_file(s) == 0) { printf("Loaded DTB from file '%s'.\n", s); rv = 0; } } if (rv == 0) { s = getenv("fdt_overlays"); if (s == NULL) s = ub_env_get("fdt_overlays"); if (s != NULL && *s != '\0') { printf("Loading DTB overlays: '%s'\n", s); fdt_load_dtb_overlays(s); } } return (rv); }
void fixup_stdout(const char *env) { const char *str; char *ptr; int serialno; int len, no, sero; const struct fdt_property *prop; char *tmp[10]; str = ub_env_get(env); ptr = (char *)str + strlen(str) - 1; while (ptr > str && isdigit(*(str - 1))) str--; if (ptr == str) return; serialno = (int)strtol(ptr, NULL, 0); no = fdt_path_offset(fdtp, "/chosen"); if (no < 0) return; prop = fdt_get_property(fdtp, no, "stdout", &len); /* If /chosen/stdout does not extist, create it */ if (prop == NULL || (prop != NULL && len == 0)) { bzero(tmp, 10 * sizeof(char)); strcpy((char *)&tmp, "serial"); if (strlen(ptr) > 3) /* Serial number too long */ return; strncpy((char *)tmp + 6, ptr, 3); sero = fdt_path_offset(fdtp, (const char *)tmp); if (sero < 0) /* * If serial device we're trying to assign * stdout to doesn't exist in DT -- return. */ return; fdt_setprop(fdtp, no, "stdout", &tmp, strlen((char *)&tmp) + 1); fdt_setprop(fdtp, no, "stdin", &tmp, strlen((char *)&tmp) + 1); } }
void fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len) { char *end, *str; uint8_t tmp_addr[6]; int i, n; /* Extract interface number */ i = strtol(env + 3, &end, 10); if (end == (env + 3)) /* 'ethaddr' means interface 0 address */ n = 0; else n = i; if (n > TMP_MAX_ETH) return; str = ub_env_get(env); /* Convert macaddr string into a vector of uints */ fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); if (n != 0) { i = strlen(env) - 7; strncpy(ethstr + 8, env + 3, i); } /* Set actual property to a value from vect */ fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); /* Clear ethernet..XXXX.. string */ bzero(ethstr + 8, len - 8); if (n + 1 > *eth_no) *eth_no = n + 1; }
/* * Parse a device string into type, unit, slice and partition numbers. A * returned value of -1 for type indicates a search should be done for the * first loadable device, otherwise a returned value of -1 for unit * indicates a search should be done for the first loadable device of the * given type. * * The returned values for slice and partition are interpreted by * disk_open(). * * Valid device strings: For device types: * * <type_name> DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit>:<slice> DEV_TYP_STOR * <type_name><unit>:<slice>. DEV_TYP_STOR * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR * * For valid type names, see the device_types array, above. * * Slice numbers are 1-based. 0 is a wildcard. */ static void get_load_device(int *type, int *unit, int *slice, int *partition) { char *devstr; const char *p; char *endp; *type = -1; *unit = -1; *slice = 0; *partition = -1; devstr = ub_env_get("loaderdev"); if (devstr == NULL) { printf("U-Boot env: loaderdev not set, will probe all devices.\n"); return; } printf("U-Boot env: loaderdev='%s'\n", devstr); p = get_device_type(devstr, type); /* Ignore optional spaces after the device name. */ while (*p == ' ') p++; /* Unknown device name, or a known name without unit number. */ if ((*type == -1) || (*p == '\0')) { return; } /* Malformed unit number. */ if (!isdigit(*p)) { *type = -1; return; } /* Guaranteed to extract a number from the string, as *p is a digit. */ *unit = strtol(p, &endp, 10); p = endp; /* Known device name with unit number and nothing else. */ if (*p == '\0') { return; } /* Device string is malformed beyond unit number. */ if (*p != ':') { *type = -1; *unit = -1; return; } p++; /* No slice and partition specification. */ if ('\0' == *p ) return; /* Only DEV_TYP_STOR devices can have a slice specification. */ if (!(*type & DEV_TYP_STOR)) { *type = -1; *unit = -1; return; } *slice = strtoul(p, &endp, 10); /* Malformed slice number. */ if (p == endp) { *type = -1; *unit = -1; *slice = 0; return; } p = endp; /* No partition specification. */ if (*p == '\0') return; /* Device string is malformed beyond slice number. */ if (*p != '.') { *type = -1; *unit = -1; *slice = 0; return; } p++; /* No partition specification. */ if (*p == '\0') return; *partition = strtol(p, &endp, 10); p = endp; /* Full, valid device string. */ if (*endp == '\0') return; /* Junk beyond partition number. */ *type = -1; *unit = -1; *slice = 0; *partition = -1; }
int main(int argc, char *argv[]) { int rv = 0, h, i, j, devs_no; struct api_signature *sig = NULL; ulong start, now; struct device_info *di; lbasize_t rlen; if (!api_search_sig(&sig)) return -1; syscall_ptr = sig->syscall; if (syscall_ptr == NULL) return -2; if (sig->version > API_SIG_VERSION) return -3; printf("API signature found @%x\n", (unsigned int)sig); test_dump_sig(sig); printf("\n*** Consumer API test ***\n"); printf("syscall ptr 0x%08x@%08x\n", (unsigned int)syscall_ptr, (unsigned int)&syscall_ptr); /* console activities */ ub_putc('B'); printf("*** Press any key to continue ***\n"); printf("got char 0x%x\n", ub_getc()); /* system info */ test_dump_si(ub_get_sys_info()); /* timing */ printf("\n*** Timing - wait a couple of secs ***\n"); start = ub_get_timer(0); printf("\ntime: start %lu\n\n", start); for (i = 0; i < WAIT_SECS; i++) for (j = 0; j < 1000; j++) ub_udelay(1000); /* wait 1 ms */ /* this is the number of milliseconds that passed from ub_get_timer(0) */ now = ub_get_timer(start); printf("\ntime: now %lu\n\n", now); /* enumerate devices */ printf("\n*** Enumerate devices ***\n"); devs_no = ub_dev_enum(); printf("Number of devices found: %d\n", devs_no); if (devs_no == 0) return -1; printf("\n*** Show devices ***\n"); for (i = 0; i < devs_no; i++) { test_dump_di(i); printf("\n"); } printf("\n*** Operations on devices ***\n"); /* test opening a device already opened */ h = 0; if ((rv = ub_dev_open(h)) != 0) { errf("open device %d error %d\n", h, rv); return -1; } if ((rv = ub_dev_open(h)) != 0) errf("open device %d error %d\n", h, rv); ub_dev_close(h); /* test storage */ printf("Trying storage devices...\n"); for (i = 0; i < devs_no; i++) { di = ub_dev_get(i); if (di->type & DEV_TYP_STOR) break; } if (i == devs_no) printf("No storage devices available\n"); else { memset(buf, 0, BUF_SZ); if ((rv = ub_dev_open(i)) != 0) errf("open device %d error %d\n", i, rv); else if ((rv = ub_dev_read(i, buf, 1, 0, &rlen)) != 0) errf("could not read from device %d, error %d\n", i, rv); else { printf("Sector 0 dump (512B):\n"); test_dump_buf(buf, 512); } ub_dev_close(i); } /* test networking */ printf("Trying network devices...\n"); for (i = 0; i < devs_no; i++) { di = ub_dev_get(i); if (di->type == DEV_TYP_NET) break; } if (i == devs_no) printf("No network devices available\n"); else { if ((rv = ub_dev_open(i)) != 0) errf("open device %d error %d\n", i, rv); else if ((rv = ub_dev_send(i, &buf, 2048)) != 0) errf("could not send to device %d, error %d\n", i, rv); ub_dev_close(i); } if (ub_dev_close(h) != 0) errf("could not close device %d\n", h); printf("\n*** Env vars ***\n"); printf("ethact = %s\n", ub_env_get("ethact")); printf("old fileaddr = %s\n", ub_env_get("fileaddr")); ub_env_set("fileaddr", "deadbeef"); printf("new fileaddr = %s\n", ub_env_get("fileaddr")); const char *env = NULL; while ((env = ub_env_enum(env)) != NULL) printf("%s = %s\n", env, ub_env_get(env)); /* reset */ printf("\n*** Resetting board ***\n"); ub_reset(); printf("\nHmm, reset returned...?!\n"); return rv; }
/* * Parse a device string into type, unit, slice and partition numbers. A * returned value of -1 for type indicates a search should be done for the * first loadable device, otherwise a returned value of -1 for unit * indicates a search should be done for the first loadable device of the * given type. * * The returned values for slice and partition are interpreted by * disk_open(). * * Valid device strings: For device types: * * <type_name> DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET * <type_name><unit>:<slice> DEV_TYP_STOR * <type_name><unit>:<slice>. DEV_TYP_STOR * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR * * For valid type names, see the device_types array, above. * * Slice numbers are 1-based. 0 is a wildcard. */ static void get_load_device(int *type, int *unit, int *slice, int *partition) { char *devstr; const char *p; char *endp; devstr = ub_env_get("loaderdev"); if (devstr == NULL) devstr = ""; else printf("U-Boot setting: loaderdev=%s\n", devstr); p = get_device_type(devstr, type); *unit = -1; *slice = 0; *partition = -1; /* * Empty device string, or unknown device name, or a bare, known * device name. */ if ((*type == -1) || (*p == '\0')) { return; } /* Malformed unit number. */ if (!isdigit(*p)) { *type = -1; return; } /* Guaranteed to extract a number from the string, as *p is a digit. */ *unit = strtol(p, &endp, 10); p = endp; /* Known device name with unit number and nothing else. */ if (*p == '\0') { return; } /* Device string is malformed beyond unit number. */ if (*p != ':') { *type = -1; *unit = -1; return; } p++; /* No slice and partition specification. */ if ('\0' == *p ) return; /* Only DEV_TYP_STOR devices can have a slice specification. */ if (!(*type & DEV_TYP_STOR)) { *type = -1; *unit = -1; return; } *slice = strtoul(p, &endp, 10); /* Malformed slice number. */ if (p == endp) { *type = -1; *unit = -1; *slice = 0; return; } p = endp; /* No partition specification. */ if (*p == '\0') return; /* Device string is malformed beyond slice number. */ if (*p != '.') { *type = -1; *unit = -1; *slice = 0; return; } p++; /* No partition specification. */ if (*p == '\0') return; *partition = strtol(p, &endp, 10); p = endp; /* Full, valid device string. */ if (*endp == '\0') return; /* Junk beyond partition number. */ *type = -1; *unit = -1; *slice = 0; *partition = -1; }
int main(void) { struct api_signature *sig = NULL; int diskdev, i, netdev, usedev; struct open_file f; const char * loaderdev; if (!api_search_sig(&sig)) return (-1); syscall_ptr = sig->syscall; if (syscall_ptr == NULL) return (-2); if (sig->version > API_SIG_VERSION) return (-3); /* Clear BSS sections */ bzero(__sbss_start, __sbss_end - __sbss_start); bzero(__bss_start, _end - __bss_start); /* * Set up console. */ cons_probe(); printf("Compatible API signature found @%x\n", (uint32_t)sig); dump_sig(sig); dump_addr_info(); /* * Initialise the heap as early as possible. Once this is done, * alloc() is usable. The stack is buried inside us, so this is * safe. */ setheap((void *)end, (void *)(end + 512 * 1024)); /* * Enumerate U-Boot devices */ if ((devs_no = ub_dev_enum()) == 0) panic("no U-Boot devices found"); printf("Number of U-Boot devices: %d\n", devs_no); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); meminfo(); /* * March through the device switch probing for things -- sort of. * * The devsw array will have one or two items in it. If * LOADER_DISK_SUPPORT is defined the first item will be a disk (which * may not actually work if u-boot didn't supply one). If * LOADER_NET_SUPPORT is defined the next item will be a network * interface. Again it may not actually work at the u-boot level. * * The original logic was to always use a disk if it could be * successfully opened, otherwise use the network interface. Now that * logic is amended to first check whether the u-boot environment * contains a loaderdev variable which tells us which device to use. If * it does, we use it and skip the original (second) loop which "probes" * for a device. We still loop over the devsw just in case it ever gets * expanded to hold more than 2 devices (but then unit numbers, which * don't currently exist, may come into play). If the device named by * loaderdev isn't found, fall back using to the old "probe" loop. * * The original probe loop still effectively behaves as it always has: * the first usable disk device is choosen, and a network device is used * only if no disk device is found. The logic has been reworked so that * it examines (and thus lists) every potential device along the way * instead of breaking out of the loop when the first device is found. */ loaderdev = ub_env_get("loaderdev"); usedev = -1; if (loaderdev != NULL) { for (i = 0; devsw[i] != NULL; i++) { if (strcmp(loaderdev, devsw[i]->dv_name) == 0) { if (devsw[i]->dv_init == NULL) continue; if ((devsw[i]->dv_init)() != 0) continue; usedev = i; goto have_device; } } printf("U-Boot env contains 'loaderdev=%s', " "device not found.\n", loaderdev); } printf("Probing for bootable devices...\n"); diskdev = -1; netdev = -1; for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_init == NULL) continue; if ((devsw[i]->dv_init)() != 0) continue; printf("Bootable device: %s\n", devsw[i]->dv_name); if (strncmp(devsw[i]->dv_name, "disk", strlen(devsw[i]->dv_name)) == 0) { f.f_devdata = &currdev; currdev.d_dev = devsw[i]; currdev.d_type = currdev.d_dev->dv_type; currdev.d_unit = 0; currdev.d_disk.slice = 0; if (devsw[i]->dv_open(&f, &currdev) == 0) { devsw[i]->dv_close(&f); if (diskdev == -1) diskdev = i; } } else if (strncmp(devsw[i]->dv_name, "net", strlen(devsw[i]->dv_name)) == 0) { if (netdev == -1) netdev = i; } } if (diskdev != -1) usedev = diskdev; else if (netdev != -1) usedev = netdev; else panic("No bootable devices found!\n"); have_device: currdev.d_dev = devsw[usedev]; currdev.d_type = devsw[usedev]->dv_type; currdev.d_unit = 0; if (currdev.d_type == DEV_TYP_STOR) currdev.d_disk.slice = 0; printf("Current device: %s\n", currdev.d_dev->dv_name); env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), uboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ setenv("prompt", "loader>", 1); archsw.arch_getdev = uboot_getdev; archsw.arch_copyin = uboot_copyin; archsw.arch_copyout = uboot_copyout; archsw.arch_readin = uboot_readin; archsw.arch_autoload = uboot_autoload; interact(); /* doesn't return */ return (0); }
/* * This is called for every object loaded (kernel, module, dtb file, etc). The * expected return value is the next address at or after the given addr which is * appropriate for loading the given object described by type and data. On each * call the addr is the next address following the previously loaded object. * * The first call is for loading the kernel, and the addr argument will be zero, * and we search for a big block of ram to load the kernel and modules. * * On subsequent calls the addr will be non-zero, and we just round it up so * that each object begins on a page boundary. */ uint64_t uboot_loadaddr(uint_t type, void *data, uint64_t addr) { struct sys_info *si; uint64_t sblock, eblock, subldr, eubldr; uint64_t biggest_block, this_block; uint64_t biggest_size, this_size; int i; char *envstr; if (addr == 0) { /* * If the loader_kernaddr environment variable is set, blindly * honor it. It had better be right. We force interpretation * of the value in base-16 regardless of any leading 0x prefix, * because that's the U-Boot convention. */ envstr = ub_env_get("loader_kernaddr"); if (envstr != NULL) return (strtoul(envstr, NULL, 16)); /* * Find addr/size of largest DRAM block. Carve our own address * range out of the block, because loading the kernel over the * top ourself is a poor memory-conservation strategy. Avoid * memory at beginning of the first block of physical ram, * since u-boot likes to pass args and data there. Assume that * u-boot has moved itself to the very top of ram and * optimistically assume that we won't run into it up there. */ if ((si = ub_get_sys_info()) == NULL) panic("could not retrieve system info"); biggest_block = 0; biggest_size = 0; subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); for (i = 0; i < si->mr_no; i++) { if (si->mr[i].flags != MR_ATTR_DRAM) continue; sblock = roundup2((uint64_t)si->mr[i].start, KERN_ALIGN); eblock = rounddown2((uint64_t)si->mr[i].start + si->mr[i].size, KERN_ALIGN); if (biggest_size == 0) sblock += KERN_MINADDR; if (subldr >= sblock && subldr < eblock) { if (subldr - sblock > eblock - eubldr) { this_block = sblock; this_size = subldr - sblock; } else { this_block = eubldr; this_size = eblock - eubldr; } } else if (subldr < sblock && eubldr < eblock) { /* Loader is below or engulfs the sblock */ this_block = (eubldr < sblock) ? sblock : eubldr; this_size = eblock - this_block; } else { this_block = 0; this_size = 0; } if (biggest_size < this_size) { biggest_block = this_block; biggest_size = this_size; } } if (biggest_size == 0) panic("Not enough DRAM to load kernel"); #if 0 printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", (uintmax_t)biggest_block, (uintmax_t)biggest_block + biggest_size - 1, (uintmax_t)biggest_size / 1024 / 1024); #endif return (biggest_block); } return (roundup2(addr, PAGE_SIZE)); }
void fdt_platform_fixups(void) { static struct fdt_mem_region regions[UB_MAX_MR]; const char *env, *str; char *end, *ethstr; int eth_no, i, len, n; struct sys_info *si; env = NULL; eth_no = 0; ethstr = NULL; /* Apply overlays before anything else */ fdt_apply_overlays(); /* Acquire sys_info */ si = ub_get_sys_info(); while ((env = ub_env_enum(env)) != NULL) { if (strncmp(env, "eth", 3) == 0 && strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { /* * Handle Ethernet addrs: parse uboot env eth%daddr */ if (!eth_no) { /* * Check how many chars we will need to store * maximal eth iface number. */ len = strlen(STRINGIFY(TMP_MAX_ETH)) + strlen("ethernet") + 1; /* * Reserve mem for string "ethernet" and len * chars for iface no. */ ethstr = (char *)malloc(len * sizeof(char)); bzero(ethstr, len * sizeof(char)); strcpy(ethstr, "ethernet0"); } /* Extract interface number */ i = strtol(env + 3, &end, 10); if (end == (env + 3)) /* 'ethaddr' means interface 0 address */ n = 0; else n = i; if (n > TMP_MAX_ETH) continue; str = ub_env_get(env); if (n != 0) { /* * Find the length of the interface id by * taking in to account the first 3 and * last 4 characters. */ i = strlen(env) - 7; strncpy(ethstr + 8, env + 3, i); } /* Modify blob */ fdt_fixup_ethernet(str, ethstr, len); /* Clear ethernet..XXXX.. string */ bzero(ethstr + 8, len - 8); if (n + 1 > eth_no) eth_no = n + 1; } else if (strcmp(env, "consoledev") == 0) { str = ub_env_get(env); fdt_fixup_stdout(str); } } /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); /* Extract the DRAM regions into fdt_mem_region format. */ for (i = 0, n = 0; i < si->mr_no && n < nitems(regions); i++) { if (si->mr[i].flags == MR_ATTR_DRAM) { regions[n].start = si->mr[i].start; regions[n].size = si->mr[i].size; n++; } } /* Fixup memory regions */ fdt_fixup_memory(regions, n); }