/* * 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); }
int main(int argc, char * const argv[]) { int rv = 0, h, i, j, devs_no; struct api_signature *sig = NULL; ulong start, now; struct device_info *di; lbasize_t rlen; struct display_info disinfo; 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)); printf("\n*** Display ***\n"); if (ub_display_get_info(DISPLAY_TYPE_LCD, &disinfo)) { printf("LCD info: failed\n"); } else { printf("LCD info:\n"); printf(" pixel width: %d\n", disinfo.pixel_width); printf(" pixel height: %d\n", disinfo.pixel_height); printf(" screen rows: %d\n", disinfo.screen_rows); printf(" screen cols: %d\n", disinfo.screen_cols); } if (ub_display_get_info(DISPLAY_TYPE_VIDEO, &disinfo)) { printf("video info: failed\n"); } else { printf("video info:\n"); printf(" pixel width: %d\n", disinfo.pixel_width); printf(" pixel height: %d\n", disinfo.pixel_height); printf(" screen rows: %d\n", disinfo.screen_rows); printf(" screen cols: %d\n", disinfo.screen_cols); } printf("*** Press any key to continue ***\n"); printf("got char 0x%x\n", ub_getc()); /* * This only clears messages on screen, not on serial port. It is * equivalent to a no-op if no display is available. */ ub_display_clear(); /* reset */ printf("\n*** Resetting board ***\n"); ub_reset(); printf("\nHmm, reset returned...?!\n"); return rv; }
/* * Locate the blob, fix it up and return its location. */ void * fdt_fixup(void) { const char *env; char *ethstr; int chosen, err, eth_no, len; struct sys_info *si; env = NULL; eth_no = 0; ethstr = NULL; len = 0; err = fdt_setup_fdtp(); if (err) { sprintf(command_errbuf, "No valid device tree blob found!"); return (NULL); } /* Create /chosen node (if not exists) */ if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == -FDT_ERR_NOTFOUND) chosen = fdt_add_subnode(fdtp, 0, "chosen"); /* Value assigned to fixup-applied does not matter. */ if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) goto success; /* 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"); /* * 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"); } /* Modify blob */ fixup_ethernet(env, ethstr, ð_no, len); } else if (strcmp(env, "consoledev") == 0) fixup_stdout(env); } /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); /* Fixup memory regions */ fixup_memory(si); fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); success: return (fdtp); }