/* * main.c - the C entry. console up first, then the board from the dtb, * then find a payload and jump. called from start.S with x0 = dtb. * * Copyright (c) 2026 Bradley Morgan * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #define TB_VERSION "0.1" extern int tb_console_init(const void *dtb); extern void __NO_RETURN tb_boot_linux(uintptr_t ep, const void *dtb); /* * staging area for the payload. past the bootloader at the bottom of * RAM, the image header decides its final resting place. */ #define TB_LOAD_ADDR 0x40200000 static int tb_read_memory(const void *dtb, uintptr_t *base, uint32 *size) { const fdt32_t *prop; int len; int node; node = fdt_path_offset(dtb, "/memory@40000000"); if (node < 0) node = fdt_path_offset(dtb, "/memory"); if (node < 0) return -1; prop = fdt_getprop(dtb, node, "reg", &len); if (!prop || len < 12) return -1; *base = ((uintptr_t)fdt32_to_cpu(prop[0]) << 32) | fdt32_to_cpu(prop[1]); *size = fdt32_to_cpu(prop[2]); return 0; } /* * bootargs from chosen. passed straight through, tashaboot does not * rewrite the kernel command line. */ static const char *tb_get_cmdline(const void *dtb) { const char *cmdline; int len; int node; node = fdt_path_offset(dtb, "/chosen"); if (node < 0) return NULL; cmdline = fdt_getprop(dtb, node, "bootargs", &len); if (!cmdline || len <= 0) return NULL; return cmdline; } /* * tashaboot,bootfile in chosen overrides the default image name. the * host file that semihosting serves is what gets loaded. */ static const char *tb_get_bootfile(const void *dtb) { const char *bootfile; int len; int node; node = fdt_path_offset(dtb, "/chosen"); if (node < 0) return NULL; bootfile = fdt_getprop(dtb, node, "tashaboot,bootfile", &len); if (!bootfile || len <= 0) return NULL; return bootfile; } void tashaboot_main(const void *dtb) { struct tb_image img; uintptr_t mem_base = 0; uint32 mem_size = 0; const char *cmdline; const char *bootfile; int ret; if (tb_console_init(dtb)) return; dprintf(ALWAYS, "tashaboot " TB_VERSION "\n"); dprintf(ALWAYS, "dtb at %p\n", dtb); if (fdt_check_header(dtb)) { dprintf(ALWAYS, "bad dtb header, halting\n"); platform_halt(); } if (tb_read_memory(dtb, &mem_base, &mem_size)) { dprintf(ALWAYS, "no usable memory node, halting\n"); platform_halt(); } dprintf(ALWAYS, "memory %lx-%lx\n", mem_base, mem_base + mem_size); cmdline = tb_get_cmdline(dtb); if (cmdline) dprintf(ALWAYS, "cmdline: %s\n", cmdline); /* * semihosting first, it is the qemu development path. a real board * boots from flash or block storage, those loaders come later and * slot in right here. */ if (!smh_probe()) { dprintf(ALWAYS, "no semihosting host, halting\n"); platform_halt(); } bootfile = tb_get_bootfile(dtb); if (!bootfile) bootfile = "Image"; ret = tb_load_semihosting(bootfile, TB_LOAD_ADDR, mem_base, mem_size, &img); if (ret) { dprintf(ALWAYS, "load failed (%d), halting\n", ret); platform_halt(); } dprintf(ALWAYS, "loaded %llu bytes at %lx, entry %lx\n", (unsigned long long)img.size, img.load, img.ep); dprintf(ALWAYS, "jumping\n"); tb_boot_linux(img.ep, dtb); }