static void zybo_common_target_init(uint level) { status_t err; /* zybo has a spiflash on qspi */ spiflash_detect(); bdev_t *spi = bio_open("spi0"); if (spi) { /* find or create a partition table at the start of flash */ if (ptable_scan(spi, 0) < 0) { ptable_create_default(spi, 0); } struct ptable_entry entry = { 0 }; /* find and recover sysparams */ if (ptable_find("sysparam", &entry) < 0) { /* didn't find sysparam partition, create it */ ptable_add("sysparam", 0x1000, 0x1000, 0); ptable_find("sysparam", &entry); } if (entry.length > 0) { sysparam_scan(spi, entry.offset, entry.length); #if SYSPARAM_ALLOW_WRITE /* for testing purposes, put at least one sysparam value in */ if (sysparam_add("dummy", "value", sizeof("value")) >= 0) { sysparam_write(); } #endif sysparam_dump(true); } /* create bootloader partition if it does not exist */ ptable_add("bootloader", 0x20000, 0x40000, 0); printf("flash partition table:\n"); ptable_dump(); } /* recover boot arguments */ const char *cmdline = bootargs_get_command_line(); if (cmdline) { printf("command line: '%s'\n", cmdline); } /* see if we came from a bootimage */ uintptr_t bootimage_phys; size_t bootimage_size; if (bootargs_get_bootimage_pointer(&bootimage_phys, &bootimage_size) >= 0) { printf("our bootimage is at phys 0x%lx, size %zx\n", bootimage_phys, bootimage_size); void *ptr = paddr_to_kvaddr(bootimage_phys); if (ptr) { bootimage_t *bi; if (bootimage_open(ptr, bootimage_size, &bi) >= 0) { /* we have a valid bootimage, find the fpga section */ const void *fpga_ptr; size_t fpga_len; if (bootimage_get_file_section(bi, TYPE_FPGA_IMAGE, &fpga_ptr, &fpga_len) >= 0) { /* we have a fpga image */ /* lookup the physical address of the bitfile */ paddr_t pa = kvaddr_to_paddr((void *)fpga_ptr); if (pa != 0) { /* program the fpga with it*/ printf("loading fpga image at %p (phys 0x%lx), len %zx\n", fpga_ptr, pa, fpga_len); zynq_reset_fpga(); err = zynq_program_fpga(pa, fpga_len); if (err < 0) { printf("error %d loading fpga\n", err); } printf("fpga image loaded\n"); } } } } } #if WITH_LIB_MINIP /* pull some network stack related params out of the sysparam block */ uint8_t mac_addr[6]; uint32_t ip_addr = IPV4_NONE; uint32_t ip_mask = IPV4_NONE; uint32_t ip_gateway = IPV4_NONE; if (sysparam_read("net0.mac_addr", mac_addr, sizeof(mac_addr)) < (ssize_t)sizeof(mac_addr)) { /* couldn't find eth address, make up a random one */ for (size_t i = 0; i < sizeof(mac_addr); i++) { mac_addr[i] = rand() & 0xff; } /* unicast and locally administered */ mac_addr[0] &= ~(1<<0); mac_addr[0] |= (1<<1); } uint8_t use_dhcp = 0; sysparam_read("net0.use_dhcp", &use_dhcp, sizeof(use_dhcp)); sysparam_read("net0.ip_addr", &ip_addr, sizeof(ip_addr)); sysparam_read("net0.ip_mask", &ip_mask, sizeof(ip_mask)); sysparam_read("net0.ip_gateway", &ip_gateway, sizeof(ip_gateway)); minip_set_macaddr(mac_addr); gem_set_macaddr(mac_addr); if (!use_dhcp && ip_addr != IPV4_NONE) { minip_init(gem_send_raw_pkt, NULL, ip_addr, ip_mask, ip_gateway); } else { /* Configure IP stack and hook to the driver */ minip_init_dhcp(gem_send_raw_pkt, NULL); } gem_set_callback(minip_rx_driver_callback); #endif }
// return NULL for success, error string for failure const char *lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len) { struct lkb_command *lcmd; for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) { if (!strcmp(lcmd->name, cmd)) { return lcmd->handler(lkb, arg, len, lcmd->cookie); } } if (len > lkb_iobuffer_size) { return "buffer too small"; } if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) { struct ptable_entry entry; bdev_t *bdev; if (ptable_find(arg, &entry) < 0) { return "no such partition"; } if (len > entry.length) { return "partition too small"; } if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } if (!(bdev = bio_open(bootdevice))) { return "bio_open failed"; } if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) { bio_close(bdev); return "bio_erase failed"; } if (!strcmp(cmd, "flash")) { if (bio_write(bdev, lkb_iobuffer, entry.offset, len) != (ssize_t)len) { bio_close(bdev); return "bio_write failed"; } } bio_close(bdev); return NULL; } else if (!strcmp(cmd, "fpga")) { #if PLATFORM_ZYNQ unsigned *x = lkb_iobuffer; if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } for (unsigned n = 0; n < len; n+= 4) { *x = SWAP_32(*x); x++; } zynq_reset_fpga(); zynq_program_fpga(lkb_iobuffer_phys, len); return NULL; #else return "no fpga"; #endif } else if (!strcmp(cmd, "boot")) { if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } thread_resume(thread_create("ramboot", &do_ramboot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); return NULL; } else if (!strcmp(cmd, "getsysparam")) { const void *ptr; size_t len; if (sysparam_get_ptr(arg, &ptr, &len) == 0) { lkb_write(lkb, ptr, len); } return NULL; } else if (!strcmp(cmd, "reboot")) { thread_resume(thread_create("reboot", &do_reboot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); return NULL; } else { return "unknown command"; } }
// return NULL for success, error string for failure int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, size_t len, const char **result) { *result = NULL; struct lkb_command *lcmd; for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) { if (!strcmp(lcmd->name, cmd)) { *result = lcmd->handler(lkb, arg, len, lcmd->cookie); return 0; } } if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) { struct ptable_entry entry; bdev_t *bdev; if (ptable_find(arg, &entry) < 0) { size_t plen = len; /* doesn't exist, make one */ if (ptable_add(arg, plen, 0) < 0) { *result = "error creating partition"; return -1; } if (ptable_find(arg, &entry) < 0) { *result = "couldn't find partition after creating it"; return -1; } } if (len > entry.length) { *result = "partition too small"; return -1; } if (!(bdev = ptable_get_device())) { *result = "ptable_get_device failed"; return -1; } printf("lkboot: erasing partition of size %llu\n", entry.length); if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) { *result = "bio_erase failed"; return -1; } if (!strcmp(cmd, "flash")) { printf("lkboot: writing to partition\n"); void *buf = malloc(bdev->block_size); if (!buf) { *result = "memory allocation failed"; return -1; } size_t pos = 0; while (pos < len) { size_t toread = MIN(len - pos, bdev->block_size); LTRACEF("offset %zu, toread %zu\n", pos, toread); if (lkb_read(lkb, buf, toread)) { *result = "io error"; free(buf); return -1; } if (bio_write(bdev, buf, entry.offset + pos, toread) != (ssize_t)toread) { *result = "bio_write failed"; free(buf); return -1; } pos += toread; } free(buf); } } else if (!strcmp(cmd, "remove")) { if (ptable_remove(arg) < 0) { *result = "remove failed"; return -1; } } else if (!strcmp(cmd, "fpga")) { #if PLATFORM_ZYNQ void *buf = malloc(len); if (!buf) { *result = "error allocating buffer"; return -1; } /* translate to physical address */ paddr_t pa = vaddr_to_paddr(buf); if (pa == 0) { *result = "error allocating buffer"; free(buf); return -1; } if (lkb_read(lkb, buf, len)) { *result = "io error"; free(buf); return -1; } /* make sure the cache is flushed for this buffer for DMA coherency purposes */ arch_clean_cache_range((vaddr_t)buf, len); /* program the fpga */ zynq_reset_fpga(); zynq_program_fpga(pa, len); free(buf); #else *result = "no fpga"; return -1; #endif } else if (!strcmp(cmd, "boot")) { return do_boot(lkb, len, result); } else if (!strcmp(cmd, "getsysparam")) { const void *ptr; size_t len; if (sysparam_get_ptr(arg, &ptr, &len) == 0) { lkb_write(lkb, ptr, len); } } else if (!strcmp(cmd, "reboot")) { thread_resume(thread_create("reboot", &do_reboot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); } else { *result = "unknown command"; return -1; } return 0; }
// return NULL for success, error string for failure const char *lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len) { struct lkb_command *lcmd; for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) { if (!strcmp(lcmd->name, cmd)) { return lcmd->handler(lkb, arg, len, lcmd->cookie); } } if (len > lkb_iobuffer_size) { return "buffer too small"; } if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) { struct ptable_entry entry; bdev_t *bdev; if (ptable_find(arg, &entry) < 0) { size_t plen = len; /* doesn't exist, make one */ #if PLATFORM_ZYNQ /* XXX not really the right place, should be in the ptable/bio layer */ plen = ROUNDUP(plen, 256*1024); #endif off_t off = ptable_allocate(plen, 0); if (off < 0) { return "no space to allocate partition"; } if (ptable_add(arg, off, plen, 0) < 0) { return "error creating partition"; } if (ptable_find(arg, &entry) < 0) { return "couldn't find partition after creating it"; } } if (len > entry.length) { return "partition too small"; } if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } if (!(bdev = bio_open(bootdevice))) { return "bio_open failed"; } if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) { bio_close(bdev); return "bio_erase failed"; } if (!strcmp(cmd, "flash")) { if (bio_write(bdev, lkb_iobuffer, entry.offset, len) != (ssize_t)len) { bio_close(bdev); return "bio_write failed"; } } bio_close(bdev); return NULL; } else if (!strcmp(cmd, "remove")) { if (ptable_remove(arg) < 0) { return "remove failed"; } return NULL; } else if (!strcmp(cmd, "fpga")) { #if PLATFORM_ZYNQ unsigned *x = lkb_iobuffer; if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } for (unsigned n = 0; n < len; n+= 4) { *x = SWAP_32(*x); x++; } zynq_reset_fpga(); zynq_program_fpga(lkb_iobuffer_phys, len); return NULL; #else return "no fpga"; #endif } else if (!strcmp(cmd, "boot")) { if (lkb_read(lkb, lkb_iobuffer, len)) { return "io error"; } thread_resume(thread_create("boot", &do_boot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); return NULL; } else if (!strcmp(cmd, "getsysparam")) { const void *ptr; size_t len; if (sysparam_get_ptr(arg, &ptr, &len) == 0) { lkb_write(lkb, ptr, len); } return NULL; } else if (!strcmp(cmd, "reboot")) { thread_resume(thread_create("reboot", &do_reboot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); return NULL; } else { return "unknown command"; } }